[jruby~main:4ceb48ad] Get direct Java handle generation working correctly for non-public classe
- From: nicksieger@kenai.com
- To: commits@jruby.kenai.com
- Subject: [jruby~main:4ceb48ad] Get direct Java handle generation working correctly for non-public classe
- Date: Wed, 3 Mar 2010 19:50:34 +0000
Project: jruby
Repository: main
Revision: 4ceb48ade5d6aacf669680e3cab32633f08116a0
Author: nicksieger
Date: 2010-03-03 19:23:17 UTC
Link:
Log Message:
------------
fixes JRUBY-4599: Invoking private/protected java no-args method with null
argument leads to NPE
Signed-off-by: Charles Oliver Nutter <headius@headius.com>
Upgrade to rspec-1.3.0, now that JRUBY-4599 is fixed.
Eliminate unnecessary volatile boolean on RubyToJavaInvoker, to speed repeat
calls.
Get direct Java handle generation working correctly for non-public classes
with public virtual methods.
Revisions:
----------
7458b0531a68374e6d611fd1db42fd3e16b6ad84
c37037ae905b0943cce50fd09461cae73b75b121
9388909d1f6f51efbd70e5745982f597ba9e27c3
4ceb48ade5d6aacf669680e3cab32633f08116a0
Modified Paths:
---------------
spec/java_integration/methods/java_method_spec.rb
src/org/jruby/javasupport/JavaMethod.java
default.build.properties
src/org/jruby/java/invokers/RubyToJavaInvoker.java
Added Paths:
------------
build_lib/rspec-1.3.0.gem
Diffs:
------
diff --git a/spec/java_integration/methods/java_method_spec.rb
b/spec/java_integration/methods/java_method_spec.rb
index ed93479..8d50efe 100644
--- a/spec/java_integration/methods/java_method_spec.rb
+++ b/spec/java_integration/methods/java_method_spec.rb
@@ -1,4 +1,4 @@
-require 'java'
+require File.dirname(__FILE__) + "/../spec_helper"
describe "A Java object's java_method method" do
before :each do
@@ -59,4 +59,14 @@ describe "A Java object's java_method method" do
java.lang.Integer.java_method :valueOf, [Java::long]
end.should raise_error(NameError)
end
+
+ it "calls static methods" do
+ lambda {
+ import 'java_integration.fixtures.PackageStaticMethod'
+
+ method = PackageStaticMethod.java_class.declared_method_smart
:thePackageScopeMethod
+ method.accessible = true
+ method.invoke Java.ruby_to_java(nil)
+ }.should_not raise_error
+ end
end
diff --git a/src/org/jruby/javasupport/JavaMethod.java
b/src/org/jruby/javasupport/JavaMethod.java
index 22afb0d..4218aa9 100644
--- a/src/org/jruby/javasupport/JavaMethod.java
+++ b/src/org/jruby/javasupport/JavaMethod.java
@@ -226,27 +226,31 @@ public class JavaMethod extends JavaCallable {
return invokeWithExceptionHandling(method, null, arguments);
}
- Object javaInvokee = JavaUtil.unwrapJavaObject(getRuntime(),
invokee, "invokee not a java object").getValue();
+ Object javaInvokee = null;
- if (! method.getDeclaringClass().isInstance(javaInvokee)) {
- throw getRuntime().newTypeError("invokee not instance of
method's class (" +
- "got" +
javaInvokee.getClass().getName() + " wanted " +
-
method.getDeclaringClass().getName() + ")");
- }
-
- //
- // this test really means, that this is a ruby-defined subclass of a
java class
- //
- if (javaInvokee instanceof InternalJavaProxy &&
- // don't bother to check if final method, it won't
- // be there (not generated, can't be!)
- !Modifier.isFinal(method.getModifiers())) {
- JavaProxyClass jpc = ((InternalJavaProxy) javaInvokee)
- .___getProxyClass();
- JavaProxyMethod jpm;
- if ((jpm = jpc.getMethod(method.getName(), parameterTypes)) !=
null &&
- jpm.hasSuperImplementation()) {
- return invokeWithExceptionHandling(jpm.getSuperMethod(),
javaInvokee, arguments);
+ if (!isStatic()) {
+ javaInvokee = JavaUtil.unwrapJavaObject(getRuntime(), invokee,
"invokee not a java object").getValue();
+
+ if (! method.getDeclaringClass().isInstance(javaInvokee)) {
+ throw getRuntime().newTypeError("invokee not instance of
method's class (" +
+ "got" +
javaInvokee.getClass().getName() + " wanted " +
+
method.getDeclaringClass().getName() + ")");
+ }
+
+ //
+ // this test really means, that this is a ruby-defined subclass
of a java class
+ //
+ if (javaInvokee instanceof InternalJavaProxy &&
+ // don't bother to check if final method, it won't
+ // be there (not generated, can't be!)
+ !Modifier.isFinal(method.getModifiers())) {
+ JavaProxyClass jpc = ((InternalJavaProxy) javaInvokee)
+ .___getProxyClass();
+ JavaProxyMethod jpm;
+ if ((jpm = jpc.getMethod(method.getName(), parameterTypes))
!= null &&
+ jpm.hasSuperImplementation()) {
+ return invokeWithExceptionHandling(jpm.getSuperMethod(),
javaInvokee, arguments);
+ }
}
}
return invokeWithExceptionHandling(method, javaInvokee, arguments);
diff --git a/build_lib/rspec-1.2.9.gem b/build_lib/rspec-1.2.9.gem
deleted file mode 100644
index 4a712d6..0000000
Binary files a/build_lib/rspec-1.2.9.gem and /dev/null differ
diff --git a/build_lib/rspec-1.3.0.gem b/build_lib/rspec-1.3.0.gem
new file mode 100644
index 0000000..f728767
Binary files /dev/null and b/build_lib/rspec-1.3.0.gem differ
diff --git a/default.build.properties b/default.build.properties
index 4e74224..6a4caf2 100644
--- a/default.build.properties
+++ b/default.build.properties
@@ -23,7 +23,7 @@ mspec.tar.file=${build.dir}/mspec.tgz
rubyspec.1.8.dir=${rubyspec.dir}/1.8
spec.tags.dir=${spec.dir}/tags
build.lib.dir=build_lib
-rspec.gem=${build.lib.dir}/rspec-1.2.9.gem
+rspec.gem=${build.lib.dir}/rspec-1.3.0.gem
rake.gem=${build.lib.dir}/rake-0.8.7.gem
ruby.debug.gem=${build.lib.dir}/ruby-debug-0.10.3.gem
ruby.debug.base.gem=${build.lib.dir}/ruby-debug-base-0.10.3.1-java.gem
diff --git a/src/org/jruby/java/invokers/RubyToJavaInvoker.java
b/src/org/jruby/java/invokers/RubyToJavaInvoker.java
index 32d70ed..c09fce3 100644
--- a/src/org/jruby/java/invokers/RubyToJavaInvoker.java
+++ b/src/org/jruby/java/invokers/RubyToJavaInvoker.java
@@ -28,7 +28,7 @@ public abstract class RubyToJavaInvoker extends JavaMethod {
protected JavaCallable[] javaVarargsCallables;
protected int minVarargsArity = Integer.MAX_VALUE;
protected Map cache;
- protected volatile boolean initialized;
+ protected boolean initialized;
private Member[] members;
RubyToJavaInvoker(RubyModule host, Member[] members) {
@@ -59,7 +59,7 @@ public abstract class RubyToJavaInvoker extends JavaMethod {
protected abstract boolean isMemberVarArgs(Member member);
synchronized void createJavaCallables(Ruby runtime) {
- if (!initialized) { // read-volatile
+ if (!initialized) {
if (members != null) {
if (members.length == 1) {
javaCallable = createCallable(runtime, members[0]);
@@ -107,7 +107,7 @@ public abstract class RubyToJavaInvoker extends
JavaMethod {
// FIXME: No real reason to use CHM, is there?
cache = new ConcurrentHashMap(0, 0.75f, 1);
}
- initialized = true; // write-volatile
+ initialized = true;
}
}
diff --git a/src/org/jruby/javasupport/JavaMethod.java
b/src/org/jruby/javasupport/JavaMethod.java
index 4218aa9..4d697c3 100644
--- a/src/org/jruby/javasupport/JavaMethod.java
+++ b/src/org/jruby/javasupport/JavaMethod.java
@@ -64,6 +64,7 @@ import org.jruby.util.CodegenUtils;
@JRubyClass(name="Java::JavaMethod")
public class JavaMethod extends JavaCallable {
private final static boolean USE_HANDLES =
RubyInstanceConfig.USE_GENERATED_HANDLES;
+ private final static boolean HANDLE_DEBUG = false;
private final Method method;
private final Handle handle;
private final JavaUtil.JavaConverter returnConverter;
@@ -93,6 +94,48 @@ public class JavaMethod extends JavaCallable {
boolean methodIsPublic = Modifier.isPublic(method.getModifiers());
boolean classIsPublic =
Modifier.isPublic(method.getDeclaringClass().getModifiers());
+ // try to find a "totally" public version of the method using
superclasses and interfaces
+ if (methodIsPublic && !classIsPublic) {
+ if (HANDLE_DEBUG) System.out.println("Method " + method + " is
not on a public class, searching for a better one");
+ Method newMethod = method;
+ Class newClass = method.getDeclaringClass();
+
+ OUTER: while (newClass != null) {
+ // try class
+ try {
+ if (HANDLE_DEBUG) System.out.println("Trying to find " +
method + " on " + newClass);
+ newMethod = newClass.getMethod(method.getName(),
method.getParameterTypes());
+
+ // got it; break if this class is public
+ if
(Modifier.isPublic(newMethod.getDeclaringClass().getModifiers())) {
+ break;
+ }
+ } catch (NoSuchMethodException nsme) {
+ }
+
+ // try interfaces
+ for (Class ifc : newClass.getInterfaces()) {
+ try {
+ if (HANDLE_DEBUG) System.out.println("Trying to find
" + method + " on " + ifc);
+ newMethod = ifc.getMethod(method.getName(),
method.getParameterTypes());
+ break OUTER;
+ } catch (NoSuchMethodException nsme) {
+ }
+ }
+
+ // go to superclass
+ newClass = newClass.getSuperclass();
+ newMethod = null;
+ }
+
+ if (newMethod != null) {
+ if (HANDLE_DEBUG) System.out.println("Found a better method
target: " + newMethod);
+ method = newMethod;
+ methodIsPublic = Modifier.isPublic(method.getModifiers());
+ classIsPublic =
Modifier.isPublic(method.getDeclaringClass().getModifiers());
+ }
+ }
+
// prepare a faster handle if handles are enabled and the method and
class are public
Handle tmpHandle = null;
try {
@@ -110,6 +153,11 @@ public class JavaMethod extends JavaCallable {
} catch (ClassNotFoundException cnfe) {
tmpHandle = null;
}
+
+ if (tmpHandle == null) {
+ if (HANDLE_DEBUG) System.out.println("did not use handle for " +
method);
+ }
+
handle = tmpHandle;
// Special classes like Collections.EMPTY_LIST are inner classes
that are private but
|
[jruby~main:4ceb48ad] Get direct Java handle generation working correctly for non-public classe |
nicksieger | 03/03/2010 |





