Module: TreeHaver::Backends::Java

Defined in:
lib/tree_haver/backends/java.rb

Overview

Java backend for JRuby using jtreesitter (java-tree-sitter)

This backend integrates with jtreesitter JARs on JRuby, leveraging JRuby’s native Java integration for optimal performance.

Features

jtreesitter (java-tree-sitter) provides Java bindings to tree-sitter and supports:

  • Parsing source code into syntax trees

  • Incremental parsing via Parser.parse(Tree, String)

  • The Query API for pattern matching

  • Tree editing for incremental re-parsing

Version Requirements

  • jtreesitter >= 0.26.0 (required)

  • tree-sitter runtime library >= 0.26.0 (must match jtreesitter version)

Older versions of jtreesitter are NOT supported due to API changes.

Platform Compatibility

  • MRI Ruby: ✗ Not available (no JVM)

  • JRuby: ✓ Full support (native Java integration)

  • TruffleRuby: ✗ Not available (jtreesitter requires JRuby’s Java interop)

Installation

  1. Download jtreesitter 0.26.0+ JAR from Maven Central: central.sonatype.com/artifact/io.github.tree-sitter/jtreesitter

  2. Set the environment variable to point to the JAR directory: export TREE_SITTER_JAVA_JARS_DIR=/path/to/jars

  3. Use JRuby to run your code: jruby -e “require ‘tree_haver’; puts TreeHaver::Backends::Java.available?”

Defined Under Namespace

Classes: Language, Node, Parser, Tree

Constant Summary collapse

JAVA_PACKAGE =

The Java package for java-tree-sitter

"io.github.treesitter.jtreesitter"

Class Method Summary collapse

Class Method Details

.add_jars_from_env!void

This method returns an undefined value.

Attempt to append JARs from TREE_SITTER_JAVA_JARS_DIR to JRuby classpath and configure native library path from TREE_SITTER_RUNTIME_LIB

If the environment variable is set and points to a directory, all .jar files in that directory (recursively) are added to the JRuby classpath.

Examples:

ENV["TREE_SITTER_JAVA_JARS_DIR"] = "/path/to/java-tree-sitter/jars"
TreeHaver::Backends::Java.add_jars_from_env!


80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/tree_haver/backends/java.rb', line 80

def add_jars_from_env!
  # :nocov:
  # This method requires JRuby and cannot be tested on MRI/CRuby.
  # JRuby-specific CI jobs would test this code.
  require "java"

  # Add JARs to classpath
  dir = ENV["TREE_SITTER_JAVA_JARS_DIR"]
  if dir && Dir.exist?(dir)
    Dir[File.join(dir, "**", "*.jar")].each do |jar|
      next if $CLASSPATH.include?(jar)
      $CLASSPATH << jar
    end
  end

  # Configure native library path for libtree-sitter
  # java-tree-sitter uses JNI and needs to find the native library
  configure_native_library_path!
  # :nocov:
rescue LoadError
  # ignore; not JRuby or Java bridge not available
end

.available?Boolean

Check if the Java backend is available

Returns true if running on JRuby and java-tree-sitter classes can be loaded. Automatically attempts to load JARs from ENV if set.

Examples:

if TreeHaver::Backends::Java.available?
  puts "Java backend is ready"
end

Returns:

  • (Boolean)

    true if Java backend is available



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/tree_haver/backends/java.rb', line 138

def available?
  return @loaded if @load_attempted
  @load_attempted = true
  @loaded = false
  @load_error = nil

  return false unless defined?(RUBY_ENGINE) && RUBY_ENGINE == "jruby"

  # :nocov:
  # Everything below requires JRuby and cannot be tested on MRI/CRuby.
  # JRuby-specific CI jobs would test this code.
  begin
    require "java"
  rescue LoadError
    @load_error = "JRuby java bridge not available"
    return false
  end

  # Optionally augment classpath and configure native library path
  add_jars_from_env!

  # Try to load the java-tree-sitter classes
  # Load Parser first as it doesn't trigger native library loading
  # Language class triggers native lib loading in its static initializer
  begin
    # These classes don't require native library initialization
    @java_classes[:Parser] = ::Java::IoGithubTreesitterJtreesitter::Parser
    @java_classes[:Tree] = ::Java::IoGithubTreesitterJtreesitter::Tree
    @java_classes[:Node] = ::Java::IoGithubTreesitterJtreesitter::Node
    @java_classes[:InputEdit] = ::Java::IoGithubTreesitterJtreesitter::InputEdit
    @java_classes[:Point] = ::Java::IoGithubTreesitterJtreesitter::Point

    # Language class may fail if native library isn't found - try it last
    # and provide a helpful error message
    begin
      @java_classes[:Language] = ::Java::IoGithubTreesitterJtreesitter::Language
    rescue NameError => e
      # Language failed but other classes loaded - native lib issue
      @load_error = "Language class failed to initialize (native library issue): #{e.message}"
      # Clear loaded classes since we can't fully function without Language
      @java_classes.clear
      return false
    end

    @loaded = true
  rescue NameError => e
    @load_error = "java-tree-sitter classes not found: #{e.message}"
    @loaded = false
  end

  @loaded
  # :nocov:
end

.capabilitiesHash{Symbol => Object}

Get capabilities supported by this backend

Examples:

TreeHaver::Backends::Java.capabilities
# => { backend: :java, parse: true, query: true, bytes_field: true, incremental: true }

Returns:

  • (Hash{Symbol => Object})

    capability map



224
225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/tree_haver/backends/java.rb', line 224

def capabilities
  # :nocov:
  # This method returns meaningful data only on JRuby when java-tree-sitter is available.
  return {} unless available?
  {
    backend: :java,
    parse: true,
    query: true, # java-tree-sitter supports the Query API
    bytes_field: true,
    incremental: true, # java-tree-sitter supports Parser.parse(Tree, String)
  }
  # :nocov:
end

.configure_native_library_path!void

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This method returns an undefined value.

Configure java.library.path to include the directory containing libtree-sitter



107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/tree_haver/backends/java.rb', line 107

def configure_native_library_path!
  # :nocov:
  # This method requires JRuby and cannot be tested on MRI/CRuby.
  lib_path = ENV["TREE_SITTER_RUNTIME_LIB"]
  return unless lib_path && File.exist?(lib_path)

  lib_dir = File.dirname(lib_path)
  current_path = java.lang.System.getProperty("java.library.path") || ""

  unless current_path.include?(lib_dir)
    new_path = current_path.empty? ? lib_dir : "#{lib_dir}:#{current_path}"
    java.lang.System.setProperty("java.library.path", new_path)

    # Also set jna.library.path in case it uses JNA
    java.lang.System.setProperty("jna.library.path", new_path)
  end
  # :nocov:
rescue => _error
  # Ignore errors setting library path
end

.java_classesHash

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Get the loaded Java classes

Returns:

  • (Hash)

    the Java class references



214
215
216
# File 'lib/tree_haver/backends/java.rb', line 214

def java_classes
  @java_classes
end

.load_errorString?

Get the last load error message (for debugging)

Returns:

  • (String, nil)

    the error message or nil if no error



195
196
197
# File 'lib/tree_haver/backends/java.rb', line 195

def load_error
  @load_error
end

.reset!void

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This method returns an undefined value.

Reset the load state (primarily for testing)



203
204
205
206
207
208
# File 'lib/tree_haver/backends/java.rb', line 203

def reset!
  @load_attempted = false
  @loaded = false
  @load_error = nil
  @java_classes = {}
end

.runtime_lookupObject?

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Get the cached runtime library SymbolLookup

Returns:

  • (Object, nil)

    the SymbolLookup for libtree-sitter.so



59
60
61
# File 'lib/tree_haver/backends/java.rb', line 59

def runtime_lookup
  @runtime_lookup
end

.runtime_lookup=(lookup) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Set the cached runtime library SymbolLookup

Parameters:

  • lookup (Object)

    the SymbolLookup



66
67
68
# File 'lib/tree_haver/backends/java.rb', line 66

def runtime_lookup=(lookup)
  @runtime_lookup = lookup
end