Integrating with Java inner classes?

Below is a simple script (using JRuby 1.1.4 on Win2K) that tries to use
the StringTemplate JAR. Things seem to work when trying to use Java
classes from the JAR that don’t have inner classes.

But…I’m rewarded with a ‘cannot link Java class
org.antlr.stringtemplate.StringTemplate’ exception when trying to use
the StringTemplate class that has 2 final static inner classes.

There’s a decent chance I overlooked some bit-o-info on the wiki site,
but what am I missing?

Thanks, Jon

===================================

begin
raise LoadError, ‘missing JRuby’ unless RUBY_PLATFORM == ‘java’
require ‘java’
require ‘D:/Jon/My Documents/JavaDev/antlr/lib/stringtemplate-3.2.jar’
rescue LoadError => e
puts “#{e.message}; exiting…”
exit -1
end

this causes a NameError saying cannot link the class.

error thrown from

$JRUBY_HOME/lib/ruby/1.8/rubygems/custom_require.rb:27

in ‘method_missing’

#import org.antlr.stringtemplate.StringTemplate

why is there nothing in the STModule.constants array after this?

module STModule
include_package org.antlr.stringtemplate
end

but there’s a Java::OrgAntlr and Java::OrgAntlrStringtemplate?

if Java.constants.index(‘OrgAntlrStringtemplate’)
ST = Java::OrgAntlrStringtemplate

begin
# can use a class that doesn’t have inner classes
aiw = ST::AutoIndentWriter.new(Java::JavaIo::PrintWriter.new(
Java::JavaLang::System.out)) # yuck!
puts “Indentation = #{aiw.get_indentation_width}”

# can partially implement a Java interface in a Ruby class
class MyListener
  include ST::StringTemplateErrorListener
  def warning(msg)
    puts msg
  end
end
MyListener.new.warning '[WARNING] just testing...'

# but can't seem to use a class with inner classes :(
st = ST::StringTemplate.new 'Hello $name$ from StringTemplate!'
st.set_attribute 'name', 'Someone'

rescue Exception => e
puts e.message
end

end


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

Try changing the argument to “import” to be a string:

import ‘org.antlr.stringtemplate.StringTemplate’

The wiki is a little misleading. When you do:

import java.lang.System

java is already a pre-defined object in JRuby, defined in “require
‘java’”.

java
=> Java::Java
java.class
=> Module

But when you require your Jar, you don’t get a similar object. So the
wiki is misleading, it’s showing the special case (extra sugar that’s
only in the built-in java libraries), not the general case. Of course,
the special case is the most common…

Best,
Martin

Jon wrote:

this causes a NameError saying cannot link the class.

if Java.constants.index(‘OrgAntlrStringtemplate’)
include ST::StringTemplateErrorListener
puts e.message
end

end


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

It doesn’t seem to matter that the arg to import be a string.

I’ve now got this test code in file ‘jruby-st2.rb’ run with ‘jruby
jruby-st2.rb’ from the command line. The first import works fine.

begin
raise LoadError, ‘missing JRuby’ unless RUBY_PLATFORM == ‘java’
require ‘java’
require ‘D:/Jon/My Documents/JavaDev/antlr/lib/stringtemplate-3.2.jar’
rescue LoadError => e
puts “#{e.message}; exiting…”
exit -1
end

import ‘org.antlr.stringtemplate.AutoIndentWriter’
puts ‘got it’ if Java.constants.include? ‘OrgAntlrStringtemplate’

import ‘org.antlr.stringtemplate.StringTemplate’

But…the 2nd import of the StringTemplate class with the 2 final
static inner classes doesn’t work and I get the following.

(eval):1:in binding': cannot link Java class org.antlr.stringtemplate.StringTemplate (NameError) from E:/jruby/lib/ruby/site_ruby/1.8/builtin/javasupport/core_ext/object.rb:67:in eval’
from
E:/jruby/lib/ruby/site_ruby/1.8/builtin/javasupport/core_ext/object.rb:67:in
include_class' from E:/jruby/lib/ruby/site_ruby/1.8/builtin/javasupport/core_ext/object.rb:38:in each’
from
E:/jruby/lib/ruby/site_ruby/1.8/builtin/javasupport/core_ext/object.rb:38:in
include_class' from E:/jruby/lib/ruby/site_ruby/1.8/builtin/javasupport/core_ext/object.rb:81:in java_import’
from jruby-st2.rb:32

Note, I also have MRI (One Click Installer) and 1.9 in addition to JRuby
installed on this machine. I’m checking to see if path issues may be
causing this problem, but I’m not sure I understand why the simple test
code above isn’t working.

On Wed, 17 Sep 2008 09:22:59 -0400
“Martin C. Martin” [email protected] wrote:

java
Martin

end

# can partially implement a Java interface in a Ruby class
st.set_attribute 'name', 'Someone'

To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

This looks like a Java Integration error. One other thing
to try is to test this against JRuby 1.1.3 since we made substantial
changes to Java Integration for 1.1.4 internally. That would be a
good data point.

-Tom

Tried with 1.1.3 and still got the failure, although on 1.1.3 I got an
error message (still a NameError) that was substantially less detailed
than with 1.1.4.

For grins, I also tried placing the StringTemplate JAR in a dir without
spaces but got the same failure.


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

Do I just need antlr downloaded to run this script to reproduce the
error?

Could you file a bug with instructions to reproduce (the simpler the
better)? This looks like a Java Integration error. One other thing
to try is to test this against JRuby 1.1.3 since we made substantial
changes to Java Integration for 1.1.4 internally. That would be a
good data point.

-Tom

On Tue, Sep 16, 2008 at 7:38 PM, Jon [email protected] wrote:

exit -1
(eval):1:in `binding’: cannot link Java class org.antlr.stringtemplate.StringTemplate (NameError)

the special case is the most common…

rescue LoadError => e
module STModule
Java::JavaLang::System.out)) # yuck!

To unsubscribe from this list, please visit:


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email


Blog: http://www.bloglines.com/blog/ThomasEEnebo
Email: [email protected] , [email protected]


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

Bug submitted → http://jira.codehaus.org/browse/JRUBY-3000

Let me know if you need more info or clarification

Jon


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

On Wed, 17 Sep 2008 08:41:47 -0700
“Thomas E Enebo” [email protected] wrote:

Do I just need antlr downloaded to run this script to reproduce the error?

Could you file a bug with instructions to reproduce (the simpler the
better)? This looks like a Java Integration error. One other thing
to try is to test this against JRuby 1.1.3 since we made substantial
changes to Java Integration for 1.1.4 internally. That would be a
good data point.

You only need the stringtemplate JAR itself from the distribution
http://www.stringtemplate.org/download/stringtemplate-3.2.tar.gz You do
not need antlr or the antlr runtime for this scenario.

I will file a bug and will use the previous simple script that attempts
an ‘import’ on the class after a ‘require’ of the jar.

Also puzzling in this case is that attempting an ‘include_package’ in a
custom Ruby module ended up with constants in the Java.constants array
but not the custom Ruby module constants array. Don’t know if this
tangential though or my misunderstanding of things.

I’ll download and try with 1.1.3 and provide an update.

Jon


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

False alarm. My code bug, not a JRuby Java integration bug in my
opinion.

Although I’ve discovered something interesting on JRuby’s dependency
handling vs. Groovy’s. For anyone curious with reading more, I’d be
interested in hearing feedback from more experienced in Ruby/JRuby.

In investigating StringTemplate, Groovy, and JRuby for a new project I
started toying with the StringTemplate API by putting the JAR in
Groovy’s lib dir and running code like

import org.antlr.stringtemplate.StringTemplateGroup
import org.antlr.stringtemplate.StringTemplate

// create a new group using the named templates in the template group
file
stg = new StringTemplateGroup(new FileReader(‘templates.stg’))
assert stg.getName() == ‘intro’ : ‘Unable to load correct template
group’

// get the hello(salutation, name) template and render it with data
st = stg.getInstanceOf(‘hello’)
assert st.getName() == ‘hello’ : ‘Unable to load correct template’

st.setAttribute ‘salutation’, ‘Hello’
st.setAttribute ‘name’, ‘Bubba Waz’

attrs = st.getAttributes()
assert attrs[‘salutation’] == ‘Hello’ : ‘Attribute corruption’
assert attrs[‘name’] == ‘Bubba Waz’ : ‘Unable to set attribute’

expected = ‘Hello, Bubba Waz from StringTemplate!’
assert st.toString() == expected : ‘Unexpected template output’

…then I started with JRuby and assumed I could also use the
StringTemplate API from JRuby just as I had from Groovy, but needed to
‘require’ just the StringTemplate JAR.

From the previous messages, my code sample blew up when trying to access
either StringTemplateGroup or StringTemplate (both have inner classes)
from JRuby. The bottom line was that I forgot to ‘require’ the ANTLR
JAR that StringTemplate apparently needs at runtime (I’m confirming this
in other languages)

Now here’s where it gets interesting, at least to me…

So why does the Groovy code with only a reference to the StringTemplate
JAR and not the ANTLR JAR work? Maybe my code accessed so little of the
API that it the code really didn’t have a runtime dependency on the
classes in the ANTLR JAR even thought StringTemplate in whole may be
dependent upon ANTLR classes.

This gives me the same queasy cool feeling I when I found out I could
open up Ruby’s String and infect it with my chatter_like_monkeys()
method.

It’s almost as if the current Groovy implementation has a form of
dynamic linking that allows it to be a bit more dynamic with regard to
its runtime dependencies, where the current JRuby linking behavior may
be a bit more eager in resolving/understanding its runtime dependencies.

I’m not at all interested in the boring discussion of compile-time
checking vs. run-time checking that’s all over the web. But I do find
it very cool that runtime dependency resolution can be made even more
dynamic based upon context.

I’m speculating on all this of course as I haven’t dug into it in enough
detail yet. I’m really interested in digging into the real run-time
dependencies of the 2 StringTemplate classes and see how Scala and Java
handle this case…as well as seeing how MRI 1.8 and 1.9 deal with
similar situations.

I’d love to hear more from others on this issue…probably not on this
thread since it has very little to do with the original subject title.
Feel free to contact me privately via email if you want to discuss.

Now to figure out how to remove the red herring bug I filed on JIRA
yesterday :frowning:

Jon


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

Jon wrote:

False alarm. My code bug, not a JRuby Java integration bug in my opinion.

assert stg.getName() == ‘intro’ : ‘Unable to load correct template group’

Small simplification: in Groovy, you can just do stg.name

attrs = st.getAttributes()

Similarly, st.attributes

So why does the Groovy code with only a reference to the StringTemplate JAR and not the ANTLR JAR work? Maybe my code accessed so little of the API that it the code really didn’t have a runtime dependency on the classes in the ANTLR JAR even thought StringTemplate in whole may be dependent upon ANTLR classes.

Groovy uses ANTLR for parsing, so I think it adds the jar to the path.

In the directory that contains “groovysh” and “groovy”, there’s a script
called “startGroovy” that those two call, which is where java in
invoked. I think it’s in the groovy all jar.

This gives me the same queasy cool feeling I when I found out I could open up Ruby’s String and infect it with my chatter_like_monkeys() method.

It’s almost as if the current Groovy implementation has a form of dynamic linking that allows it to be a bit more dynamic with regard to its runtime dependencies, where the current JRuby linking behavior may be a bit more eager in resolving/understanding its runtime dependencies.

Actually, it’s the opposite. Groovy compiles the bytecode for a class
from the definition, and can do this ahead of time with groovyc. JRuby
defers bytecode generation until you create an instance of a class.
jrubyc creates a .class file that represents the script, but not for any
classes in the script.


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

Martin C. Martin wrote:

attrs = st.getAttributes()

Similarly, st.attributes

Ditto on both for JRuby.

Actually, it’s the opposite. Groovy compiles the bytecode for a class
from the definition, and can do this ahead of time with groovyc. JRuby
defers bytecode generation until you create an instance of a class.
jrubyc creates a .class file that represents the script, but not for any
classes in the script.

Minor correction: Ruby code may end up as bytecode if it’s called
enough, but under normal execution most code is interpreted at first.
Whether a class has been defined or not is unrelated.

And the .class that jrubyc produces is basically just the compile script
from top to bottom. Ruby’s representation of classes and methods is
somewhat more fluid than Groovy’s, so there’s rarely a 1:1
correspondence in JRuby between a Java class and a Ruby class.

  • Charlie

To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

Groovy uses ANTLR for parsing, so I think it adds the jar to the path.

ah yes…there’s the lib/antlr-2.7.6.jar and inside the groovy jar’s
manifest.mf is “Require-Bundle: antlr”

thanks for the info re: bytecode generation differences.


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email