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

Tree/Node Architecture

This backend (like all tree-sitter backends: MRI, Rust, FFI, Java) does NOT define its own Tree or Node classes at the Ruby level. Instead:

  • Parser#parse returns raw Java tree objects (via JRuby interop)

  • These are wrapped by TreeHaver::Tree (inherits from Base::Tree)

  • ‘TreeHaver::Tree#root_node` wraps raw nodes in TreeHaver::Node

This differs from pure-Ruby backends (Citrus, Prism, Psych) which define their own Backend::X::Tree and Backend::X::Node classes.

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!


97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/tree_haver/backends/java.rb', line 97

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

Returns:

  • (Boolean)


158
159
160
161
162
# File 'lib/tree_haver/backends/java.rb', line 158

def available?
  return @loaded if @load_attempted # rubocop:disable ThreadSafety/ClassInstanceVariable
  @load_attempted = true # rubocop:disable ThreadSafety/ClassInstanceVariable
  @loaded = check_availability # rubocop:disable ThreadSafety/ClassInstanceVariable
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



217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/tree_haver/backends/java.rb', line 217

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



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/tree_haver/backends/java.rb', line 124

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



207
208
209
# File 'lib/tree_haver/backends/java.rb', line 207

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



199
200
201
# File 'lib/tree_haver/backends/java.rb', line 199

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)



168
169
170
171
172
173
174
# File 'lib/tree_haver/backends/java.rb', line 168

def reset!
  @load_attempted = false # rubocop:disable ThreadSafety/ClassInstanceVariable
  @loaded = false # rubocop:disable ThreadSafety/ClassInstanceVariable
  @load_error = nil # rubocop:disable ThreadSafety/ClassInstanceVariable
  @loader = nil # rubocop:disable ThreadSafety/ClassInstanceVariable
  @java_classes = {} # rubocop:disable ThreadSafety/ClassInstanceVariable
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



76
77
78
# File 'lib/tree_haver/backends/java.rb', line 76

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



83
84
85
# File 'lib/tree_haver/backends/java.rb', line 83

def runtime_lookup=(lookup)
  @runtime_lookup = lookup
end