... bytes and babes of JRuby

When Ruby Does Java Privacy

Make sure you have JRuby or higher when trying out the samples.

Ruby has little respect for privacy or private state. There sure is “sugar” such as private or private_constant but none of these really hide anything away much, it’s a very flexible language after all. Java on the other hand gets a bit restrictive, with respect for private visibility enforced by the compiler.

Let’s see how JRuby fits the two together in the context of retrieving classes.

Obviously, public Java classes simply work as if it they were from Ruby-land :

java.util.Map::Entry # Map.Entry
java.util.Map.module_eval do
  Entry.class_eval do
    def value?; ! value.nil? end

Contrary, private or package-only Java classes are hidden as if they did not exist.

Ruby has private_constant to make sure constants are only visible in the declared (module) context but nowhere else.

module ObjectUtils
  NULL =
  private_constant :NULL
  def null?; self.equal? NULL end
ObjectUtils::NULL # NameError

Turns out this fits non-public Java classes nicely. Let’s showcase an example.

Suppose we’d like to be able to detect whether a java.util.List instance is synchronized (naively assuming list types are only those available with the standard collections framework) :

# most are not synchronized e.g. java.util.ArrayList
java::util::List.module_eval do
  def synchronized?; false end
# old pal java.util.Vector synchronized since day 1
java::util::Vector.class_eval do
  def synchronized?; true end
# a java.util.Collections.SynchronizedList wrapper
# returned from java.util.Collections.synchronizedList
java::util::Collections::SynchronizedList # NameError !
# but accessing inside its enclosing class works :
class java::util::Collections
  def SynchronizedList.synchronized?; true end

As expected the non-public inner SynchronizedList in Ruby scripts behaves similarly to how it does in raw Java - only accessible in the enclosing class and not being part of the exported API.