diff --git a/js/rhino/src/org/mozilla/javascript/NativeJavaMethod.java b/js/rhino/src/org/mozilla/javascript/NativeJavaMethod.java index db5605c9dbfa..8f0ed215803d 100644 --- a/js/rhino/src/org/mozilla/javascript/NativeJavaMethod.java +++ b/js/rhino/src/org/mozilla/javascript/NativeJavaMethod.java @@ -220,44 +220,68 @@ public class NativeJavaMethod extends NativeFunction implements Function { } javaObject = ((Wrapper) o).unwrap(); } - try { - if (debug) { - printDebug("Calling ", meth, args); - } + retry: + for (int attempt=0; ; attempt++) { + try { + if (debug) { + printDebug("Calling ", meth, args); + } - /** - * Due to a bug in Suns VM, public methods in private - * classes are not accessible by default (Sun Bug #4071593). - * We have to explicitly set the method accessible beforehand - */ - meth.setAccessible(true); - Object retval = meth.invoke(javaObject, args); - Class staticType = meth.getReturnType(); + Object retval = meth.invoke(javaObject, args); + Class staticType = meth.getReturnType(); - if (debug) { - Class actualType = (retval == null) ? null : retval.getClass(); - System.err.println(" ----- Returned " + retval + - " actual = " + actualType + - " expect = " + staticType); - } + if (debug) { + Class actualType = (retval == null) ? null + : retval.getClass(); + System.err.println(" ----- Returned " + retval + + " actual = " + actualType + + " expect = " + staticType); + } - Object wrapped = NativeJavaObject.wrap(scope, retval, staticType); + Object wrapped = NativeJavaObject.wrap(scope, retval, staticType); - if (debug) { - Class actualType = (wrapped == null) ? null : wrapped.getClass(); - System.err.println(" ----- Wrapped as " + wrapped + - " class = " + actualType); - } + if (debug) { + Class actualType = (wrapped == null) ? null + : wrapped.getClass(); + System.err.println(" ----- Wrapped as " + wrapped + + " class = " + actualType); + } - if (wrapped == Undefined.instance) + if (wrapped == Undefined.instance) + return wrapped; + if (wrapped == null && staticType == Void.TYPE) + return Undefined.instance; return wrapped; - if (wrapped == null && staticType == Void.TYPE) - return Undefined.instance; - return wrapped; - } catch (IllegalAccessException accessEx) { - throw Context.reportRuntimeError(accessEx.getMessage()); - } catch (InvocationTargetException e) { - throw JavaScriptException.wrapException(scope, e); + } catch (IllegalAccessException accessEx) { + if (Modifier.isPublic(meth.getModifiers()) && attempt == 0) { + /** + * Due to a bug in Suns VM, public methods in private + * classes are not accessible by default (Sun Bug #4071593). + * We have to explicitly set the method accessible + * via meth.setAccessible(true) but we have to use + * reflection because the setAccessible() in Method is + * not available under jdk 1.1. We wait until a failure + * to retry to avoid the overhead of this call on cases + * that don't require it. + */ + if (method_setAccessible != null) { + Object[] args_wrapper = { Boolean.TRUE }; + try { + method_setAccessible.invoke(meth, args_wrapper); + } + catch (IllegalAccessException ex) { } + catch (IllegalArgumentException ex) { } + catch (InvocationTargetException ex) { } + } + continue retry; + } + throw Context.reportRuntimeError( + "While attempting to call \"" + meth.getName() + + "\" in class \"" + meth.getDeclaringClass().getName() + + "\" receieved " + accessEx.toString()); + } catch (InvocationTargetException e) { + throw JavaScriptException.wrapException(scope, e); + } } } @@ -507,6 +531,17 @@ public class NativeJavaMethod extends NativeFunction implements Function { return methods; } + // Utility to call Class.getMethod and get null instead of thrown exceptions + private static Method getMethod(Class cl, String name, Class[] signature) { + try { + return cl.getMethod(name, signature); + } + catch (NoSuchMethodException ex) { } + catch (SecurityException ex) { } + return null; + } + + private static final boolean debug = false; private static void printDebug(String msg, Member member, Object[] args) { @@ -519,5 +554,10 @@ public class NativeJavaMethod extends NativeFunction implements Function { } Method methods[]; + + private static final Method method_setAccessible + = getMethod(Method.class, + "setAccessible", new Class[] { Boolean.TYPE }); + }