Details

    • Type: Bug Bug
    • Status: Closed Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: JRuby 1.6.1
    • Fix Version/s: JRuby 1.6.3
    • Component/s: None
    • Labels:
      None
    • Number of attachments :
      0

      Description

      This worked previously in 1.6.0, breaks in 1.6.1

      Problem is the java class name generated by jrubyc is incorrect.

      snack(~) % cat test.rb
      puts "Hello world!"
      snack(~) % jrubyc test.rb
      stringsnack(~) % strings ./test.class | head -1
      6ruby/jit/FILE_11ED3A61A4256FA54D81BAAFFD4F6A02089FE4DB
      snack(~) % java test
      Exception in thread "main" java.lang.NoClassDefFoundError: test (wrong name: ruby/jit/FILE_11ED3A61A4256FA54D81BAAFFD4F6A02089FE4DB)
      

      And in 1.6.0 for confirmation of prior-working:

      snack(~) % rvm use 1.6.0
      Using /home/jls/.rvm/gems/jruby-1.6.0
      snack(~) % jrubyc test.rb                
      Compiling test.rb to class test
      snack(~) % !strings
      strings ./test.class | head -1
      test
      

        Activity

        Hide
        Jordan Sissel added a comment -

        For clarity, I ran into this problem while doing some usual monolithic packaging of jruby and some other code.

        I have historically set the jar entry point to be "logstash.runner" which is compiled as logstash/runner.class in the jar. This worked in 1.6.0

        If I am doing something in an unsupported way, or you have better plans for how to properly do this, I am open to alternatives

        Show
        Jordan Sissel added a comment - For clarity, I ran into this problem while doing some usual monolithic packaging of jruby and some other code. I have historically set the jar entry point to be "logstash.runner" which is compiled as logstash/runner.class in the jar. This worked in 1.6.0 If I am doing something in an unsupported way, or you have better plans for how to properly do this, I am open to alternatives
        Hide
        Charles Oliver Nutter added a comment -

        Hmm, I think you've found a hole in a fix I made for 1.6.1.

        Before 1.6, we attempted to guess the package name from the directory structure. If the directory structure contained characters that could not be mapped into a package name, we had to mangle those characters. This caused the .class files to be emitted into mangled directories, the class they contain to have a mangled package, and so on. This in turn caused applications with package-unfriendly characters to be nearly impossible to precompile.

        My fix was to make jrubyc's normal mode always emit the class as a SHA1 hashed name contained in a .class file named exactly the same as the script. JRuby's loader can handle that case and load the contained class using the appropriate SHA1 name.

        When I first started working on the JRuby AOT compiler (jrubyc) I knew that the resulting .class files would always be a little weird. They're not really a normal Java class that can be instantiated, reflected, invoked. In general I have discouraged treating jrubyc-compiled Ruby scripts as Java classes. I ALMOST made a change to have jrubyc emit files with the extension .rb.class to indicate that they're vaguely JVM class-like, but not intended to be used directly as Java classes. This idea was to address folks like you using those class files directly.

        I regret the lost of a simple "main" being in the classes, but the compiled results of jrubyc have never really been intended to look like "real" Java classes. That feature comes from jrubyc --java(c), where you could define a "main" class something like this:

        require 'java'
        
        java_package 'logstash'
        
        class Runner
          java_signature 'void main(String[])'
          def self.main(args) # args is a Java String[] still
            # call into your code as appropriate
          end
        end
        

        In the simple case, this will emit a logstash/runner.class that mostly behaves like the "main" from JRuby 1.6.0 jrubyc. There are more complex cases illustrated here:

        https://github.com/jruby/jruby/wiki/GeneratingJavaClasses

        This mechanism is intended as the proper way to generate "real" Java classes. It should work with JRuby 1.6.x and probably all 1.5.x releases too.

        Does this seem like an acceptable alternative for you guys?

        Show
        Charles Oliver Nutter added a comment - Hmm, I think you've found a hole in a fix I made for 1.6.1. Before 1.6, we attempted to guess the package name from the directory structure. If the directory structure contained characters that could not be mapped into a package name, we had to mangle those characters. This caused the .class files to be emitted into mangled directories, the class they contain to have a mangled package, and so on. This in turn caused applications with package-unfriendly characters to be nearly impossible to precompile. My fix was to make jrubyc's normal mode always emit the class as a SHA1 hashed name contained in a .class file named exactly the same as the script. JRuby's loader can handle that case and load the contained class using the appropriate SHA1 name. When I first started working on the JRuby AOT compiler (jrubyc) I knew that the resulting .class files would always be a little weird. They're not really a normal Java class that can be instantiated, reflected, invoked. In general I have discouraged treating jrubyc-compiled Ruby scripts as Java classes. I ALMOST made a change to have jrubyc emit files with the extension .rb.class to indicate that they're vaguely JVM class-like, but not intended to be used directly as Java classes. This idea was to address folks like you using those class files directly. I regret the lost of a simple "main" being in the classes, but the compiled results of jrubyc have never really been intended to look like "real" Java classes. That feature comes from jrubyc --java(c), where you could define a "main" class something like this: require 'java' java_package 'logstash' class Runner java_signature 'void main(String[])' def self.main(args) # args is a Java String[] still # call into your code as appropriate end end In the simple case, this will emit a logstash/runner.class that mostly behaves like the "main" from JRuby 1.6.0 jrubyc. There are more complex cases illustrated here: https://github.com/jruby/jruby/wiki/GeneratingJavaClasses This mechanism is intended as the proper way to generate "real" Java classes. It should work with JRuby 1.6.x and probably all 1.5.x releases too. Does this seem like an acceptable alternative for you guys?
        Hide
        Jordan Sissel added a comment -

        What you propose seems reasonable especially since (IMO) "running" a compiled ruby->java class is a bit of an edge case and fitting it into the java model (static main method on a class) seems good to me

        Show
        Jordan Sissel added a comment - What you propose seems reasonable especially since (IMO) "running" a compiled ruby->java class is a bit of an edge case and fitting it into the java model (static main method on a class) seems good to me
        Hide
        Jordan Sissel added a comment -

        For closure, I have updated the main class I run now to use the "real java"-style main class method stuff discussed above.

        Works perfectly under jruby 1.6.1

        Show
        Jordan Sissel added a comment - For closure, I have updated the main class I run now to use the "real java"-style main class method stuff discussed above. Works perfectly under jruby 1.6.1
        Hide
        Jordan Sissel added a comment -

        Nevermind, it's not working. I htink rvm lied when it said it was using jruby 1.6.1 - fixed that and I get problems now.

        Code - "foo/bar.rb"

        module Foo
          class Bar
            def self.main(args)
              p :args => args
            end
          end
        end
        

        What version of jruby?

        % which jrubyc
        /home/jls/.rvm/rubies/jruby-1.6.1/bin/jrubyc
        
        % jrubyc foo/bar.rb
        % ls foo/*.class   
        foo/bar.class
        % java foo/bar
        Exception in thread "main" java.lang.NoClassDefFoundError: foo/bar (wrong name: ruby/jit/FILE_18EE586EE1D0C6A0C46BE28F06755A3DC1AE0708)
        
        % strings foo/bar.class | head -1
        6ruby/jit/FILE_18EE586EE1D0C6A0C46BE28F06755A3DC1AE0708
        
        Show
        Jordan Sissel added a comment - Nevermind, it's not working. I htink rvm lied when it said it was using jruby 1.6.1 - fixed that and I get problems now. Code - "foo/bar.rb" module Foo class Bar def self.main(args) p :args => args end end end What version of jruby? % which jrubyc /home/jls/.rvm/rubies/jruby-1.6.1/bin/jrubyc % jrubyc foo/bar.rb % ls foo/*.class foo/bar.class % java foo/bar Exception in thread "main" java.lang.NoClassDefFoundError: foo/bar (wrong name: ruby/jit/FILE_18EE586EE1D0C6A0C46BE28F06755A3DC1AE0708) % strings foo/bar.class | head -1 6ruby/jit/FILE_18EE586EE1D0C6A0C46BE28F06755A3DC1AE0708
        Hide
        Jordan Sissel added a comment -

        Even using the 'java_package' and 'java_signature' stuff seems still not make it work.

        Show
        Jordan Sissel added a comment - Even using the 'java_package' and 'java_signature' stuff seems still not make it work.
        Hide
        Charles Oliver Nutter added a comment -

        Harumph. I am wondering if perhaps I should go back to the old mangling but still output files in the exact same dir as the .rb. That would fix the original issue, but for files without peculiar paths the .class would still be executable. I'll look into that as a fix on 1.6 branch at least.

        Show
        Charles Oliver Nutter added a comment - Harumph. I am wondering if perhaps I should go back to the old mangling but still output files in the exact same dir as the .rb. That would fix the original issue, but for files without peculiar paths the .class would still be executable. I'll look into that as a fix on 1.6 branch at least.
        Hide
        Charles Oliver Nutter added a comment -

        Ok, so the original issue was that we needed to generate the files into the same dirs, otherwise they were scattered in other dirs and didn't load properly. I originally fixed it by always generating the SHA1 hashed class name into the real .class file, which allowed the files to load (since we use the actual contained classname regardless of filename) but then the classes were not valid for loading as the "main" Java class.

        The compromise fix goes back to the old mangling and related params (prefix, etc), but always outputs the class file into a .class file alongside the .rb file. The class names should be "unique enough" because of the mangling, loadable as in all previous versions, in the same dir as the .rb files, and still executable as Java main when there's no peculiar elements in the path that require mangling.

        jruby1_6: d2b8c0d, master: dd22207

        commit dd22207a372755f6af2cd8b27580df36cf4bd6e2
        Author: Charles Oliver Nutter <headius@headius.com>
        Date:   Wed Jul 6 13:19:14 2011 -0500
        
            Fix JRUBY-5724: jrubyc generates classes with the wrong names
            
            I reverted to the old mangling but still putting .class alongside .rb. I think this may balance both worlds ok for now.
        
        Show
        Charles Oliver Nutter added a comment - Ok, so the original issue was that we needed to generate the files into the same dirs, otherwise they were scattered in other dirs and didn't load properly. I originally fixed it by always generating the SHA1 hashed class name into the real .class file, which allowed the files to load (since we use the actual contained classname regardless of filename) but then the classes were not valid for loading as the "main" Java class. The compromise fix goes back to the old mangling and related params (prefix, etc), but always outputs the class file into a .class file alongside the .rb file. The class names should be "unique enough" because of the mangling, loadable as in all previous versions, in the same dir as the .rb files, and still executable as Java main when there's no peculiar elements in the path that require mangling. jruby1_6: d2b8c0d, master: dd22207 commit dd22207a372755f6af2cd8b27580df36cf4bd6e2 Author: Charles Oliver Nutter <headius@headius.com> Date: Wed Jul 6 13:19:14 2011 -0500 Fix JRUBY-5724: jrubyc generates classes with the wrong names I reverted to the old mangling but still putting .class alongside .rb. I think this may balance both worlds ok for now.

          People

          • Assignee:
            Charles Oliver Nutter
            Reporter:
            Jordan Sissel
          • Votes:
            2 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: