{"action":"created","issue":{"url":"https://api.github.com/repos/jruby/jruby/issues/2857","labels_url":"https://api.github.com/repos/jruby/jruby/issues/2857/labels{/name}","comments_url":"https://api.github.com/repos/jruby/jruby/issues/2857/comments","events_url":"https://api.github.com/repos/jruby/jruby/issues/2857/events","html_url":"https://github.com/jruby/jruby/issues/2857","id":69779321,"number":2857,"title":"org.jruby.javasupport.JavaMethod invocation does not wrap returned JavaObject","user":{"login":"vietj","id":225674,"avatar_url":"https://avatars.githubusercontent.com/u/225674?v=3","gravatar_id":"","url":"https://api.github.com/users/vietj","html_url":"https://github.com/vietj","followers_url":"https://api.github.com/users/vietj/followers","following_url":"https://api.github.com/users/vietj/following{/other_user}","gists_url":"https://api.github.com/users/vietj/gists{/gist_id}","starred_url":"https://api.github.com/users/vietj/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/vietj/subscriptions","organizations_url":"https://api.github.com/users/vietj/orgs","repos_url":"https://api.github.com/users/vietj/repos","events_url":"https://api.github.com/users/vietj/events{/privacy}","received_events_url":"https://api.github.com/users/vietj/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/jruby/jruby/labels/java%20integration","name":"java integration","color":"000000"},{"url":"https://api.github.com/repos/jruby/jruby/labels/JRuby%201.7.x","name":"JRuby 1.7.x","color":"eb6420"},{"url":"https://api.github.com/repos/jruby/jruby/labels/JRuby%209000","name":"JRuby 9000","color":"bfe5bf"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":30,"created_at":"2015-04-21T08:14:54Z","updated_at":"2015-04-23T14:55:32Z","closed_at":null,"body":"The Vert.x 3 Ruby lang integration uses `java_class.declared_method` for dispatching the Ruby Vert.x API to the Java Vert.x API.\r\n\r\nThe `JavaMethod` object does not wrap the returned objects instance of `JavaObject`, so such objects are not usable from JRuby as they are and must be rewrapped with their corresponding JRuby wrappers.\r\n\r\nThe current implementation extends the returned `JavaMethod` object to avoid such issues:\r\n\r\n```\r\npublic class ConvertingJavaMethod extends JavaMethod {\r\n\r\n  private final Class boxedReturnType;\r\n  private final JavaUtil.JavaConverter returnConverter;\r\n\r\n  public ConvertingJavaMethod(Ruby runtime, Method method) {\r\n    super(runtime, method);\r\n    method.setAccessible(true);\r\n    if (method.getReturnType().isPrimitive() && method.getReturnType() != void.class) {\r\n      this.boxedReturnType = CodegenUtils.getBoxType(method.getReturnType());\r\n    } else {\r\n      this.boxedReturnType = method.getReturnType();\r\n    }\r\n    returnConverter = JavaUtil.getJavaConverter(method.getReturnType());\r\n  }\r\n\r\n  @Override\r\n  public IRubyObject invoke(IRubyObject[] args) {\r\n    IRubyObject ret = super.invoke(args);\r\n    if (ret instanceof JavaObject) {\r\n      ret = convertReturn(((JavaObject) ret).getValue());\r\n    }\r\n    return ret;\r\n  }\r\n\r\n  private IRubyObject convertReturn(Object result) {\r\n    if (result != null && result.getClass() != boxedReturnType) {\r\n      // actual type does not exactly match method return type, re-get converter\r\n      // FIXME: when the only autoconversions are primitives, this won't be needed\r\n      return JavaUtil.convertJavaToUsableRubyObject(getRuntime(), result);\r\n    }\r\n    return JavaUtil.convertJavaToUsableRubyObjectWithConverter(getRuntime(), result, returnConverter);\r\n  }\r\n}\r\n```\r\n\r\nSuch code is used in such way:\r\n\r\n```\r\n(Java::IoVertxLangJruby::Helper.fixJavaMethod(@j_del.java_class.declared_method(:runOnContext,Java::IoVertxCore::Handler.java_class))).invoke(@j_del,Proc.new { yield })\r\n```\r\n\r\n(the helper transforms the `JavaMethod` returned by `declared_method` to `ConvertingJavaMethod`)\r\n\r\nThe current code needs to use `method.setAccessible(true)` otherwise some Vert.x methods cannot be invoked leading to a runtime error like:\r\n\r\n```\r\norg.jruby.exceptions.RaiseException: (TypeError) illegal access on 'complete': Class org.jruby.javasupport.JavaMethod can not access a member of class io.vertx.core.impl.FutureImpl with modifiers \"public\"\r\n\tat org.jruby.javasupport.JavaMethod.invoke(org/jruby/javasupport/JavaMethod.java:257)\r\n\tat RUBY.complete(/Users/julien/java/vertx-lang-ruby/target/classes/vertx/future.rb:72)\r\n```\r\n\r\n\r\n"},"comment":{"url":"https://api.github.com/repos/jruby/jruby/issues/comments/95612449","html_url":"https://github.com/jruby/jruby/issues/2857#issuecomment-95612449","issue_url":"https://api.github.com/repos/jruby/jruby/issues/2857","id":95612449,"user":{"login":"headius","id":10135,"avatar_url":"https://avatars.githubusercontent.com/u/10135?v=3","gravatar_id":"","url":"https://api.github.com/users/headius","html_url":"https://github.com/headius","followers_url":"https://api.github.com/users/headius/followers","following_url":"https://api.github.com/users/headius/following{/other_user}","gists_url":"https://api.github.com/users/headius/gists{/gist_id}","starred_url":"https://api.github.com/users/headius/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/headius/subscriptions","organizations_url":"https://api.github.com/users/headius/orgs","repos_url":"https://api.github.com/users/headius/repos","events_url":"https://api.github.com/users/headius/events{/privacy}","received_events_url":"https://api.github.com/users/headius/received_events","type":"User","site_admin":false},"created_at":"2015-04-23T14:55:32Z","updated_at":"2015-04-23T14:55:32Z","body":"FYI we had some dependency changes last night so I pushed a new 1.7.20-SNAPSHOT."}}