Gem with declared jars

Kristian Meier edited this page Aug 16, 2012 · 1 revision

Jar dependencies for packaged gems (Proposal)

current situation

vendored jars

if gem needs a jar or more it 'vendors' those jars, i.e. package them as part of the gem. which OK for a jar which is a part of the gem in the sense it is not available as standalone jar - something like a java extension of the gem.

once the same external jar gets vendored by two different gems then it is possible (maybe not very likely) that both of these jars are loaded into the jruby-classloader.

vendored jars with check if already loaded

some gems do take this into account and check if some jar is already loaded (data-object java-gems from datamapper.org do this for example). if all the gems would do this at least the jruby classloader will have only a single version of jar loaded. which version actually gets loaded depends on the execution path of the application and when those jars get required.

getting control back and manage jar dependencies

even if the gem checks whether a jar is already loaded or not, it would be nice to manage these jars with a dependency manager of some kind. with gemspec you can declare runtime gem-dependencies as well development gem-dependencies. but for jars there is no specific place. but if you look at

requirements of gemspec

that this is the perfect place to "add" jar dependencies - as meant by requirements definition. it is less formal as the gem dependecies declaration but it is a way to do it like this

Gem::Specification.new do |s|
  s.name = 'gem_with_jar'
  s.version = '0.0.0'
  s.requirements << "jar 'org.slf4j:slf4j-api', '1.5.10'"
end

and the jar declaration is just

jar 'org.slf4j:slf4j-api', '1.5.10'

since these declaration are maven jar artifacts there is there several project which can manage such artifacts, i.e. resolve them, download the right versions, etc.

projects which obeys this declarations

jar declaration can be found inside the Jarfile/Jarfile.lock or can be found in the requirements section of the gems loaded via Gemfile/Gemfile.lock or the gemspec file(s) of the project itself.

  • jbundler in conjunction with Gemfile
  • jetty-run will setup the web-container classloader with the transitive dependency hull of all jar dependencies
  • ruby-maven when using a gemspec or Gemfile as project definition
  • gem-proxy serves gem-maven-artifact for all the gems from rubygems.org. they are mainly used by the jruby-maven-plugins

random thoughts

even if you manage the jars manually you have the control back, as long the gems do check if their jar is already loaded.

for bigger projects I am sure that is essential to manage jars in similar manner as you manage gems.

from j2ee projects it became clear to me that the first thing is to keep your classloaders clean, i.e. no duplicated jars all the way up to the bootclassloader. or that is the first thing to check when you see strange ClassDefNotFoundErrors or alike. and for that you need to control over your jars.

I guess I am a control freak and as such the current jruby-gems are a nightmare for me.