[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
  • Mysql
  • Glassfish
  • Jruby
  • Rails
  • Nblogo
Terms of Use; Privacy Policy;
© 2010, Oracle Corporation and/or its affiliates
(revision 20120518.3c65429)
 
 
Close
loading
Please Confirm
Close