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 defines Ruby wrapper classes (Java::Language, Java::Parser, Java::Tree, Java::Node) that wrap the raw jtreesitter Java objects via JRuby’s Java interop. These are **raw backend wrappers** not intended for direct use by application code.
The wrapping hierarchy is:
Java::Tree/Node (this backend) → TreeHaver::Tree/Node → Base::Tree/Node
When you use ‘TreeHaver::Parser#parse`:
-
‘Java::Parser#parse` returns a
Java::Tree(wrapper around jtreesitter Tree) -
TreeHaver::Parserwraps it inTreeHaver::Tree(adds source storage) -
‘TreeHaver::Tree#root_node` wraps
Java::NodeinTreeHaver::Node
The TreeHaver::Tree and TreeHaver::Node wrappers provide the full unified API including #children, #text, #source, #source_position, etc.
This differs from pure-Ruby backends (Citrus, Parslet, Prism, Psych) which define Tree/Node classes that directly inherit from Base::Tree/Base::Node.
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
-
Download jtreesitter 0.26.0+ JAR from Maven Central: central.sonatype.com/artifact/io.github.tree-sitter/jtreesitter
-
Set the environment variable to point to the JAR directory: export TREE_SITTER_JAVA_JARS_DIR=/path/to/jars
-
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
-
.add_jars_from_env! ⇒ void
Attempt to append JARs from TREE_SITTER_JAVA_JARS_DIR to JRuby classpath and configure native library path from TREE_SITTER_RUNTIME_LIB.
- .available? ⇒ Boolean
-
.capabilities ⇒ Hash{Symbol => Object}
Get capabilities supported by this backend.
-
.configure_native_library_path! ⇒ void
private
Configure java.library.path to include the directory containing libtree-sitter.
-
.java_classes ⇒ Hash
private
Get the loaded Java classes.
-
.load_error ⇒ String?
Get the last load error message (for debugging).
-
.reset! ⇒ void
private
Reset the load state (primarily for testing).
-
.runtime_lookup ⇒ Object?
private
Get the cached runtime library SymbolLookup.
-
.runtime_lookup=(lookup) ⇒ Object
private
Set the cached runtime library SymbolLookup.
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.
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/tree_haver/backends/java.rb', line 106 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
167 168 169 170 171 |
# File 'lib/tree_haver/backends/java.rb', line 167 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 |
.capabilities ⇒ Hash{Symbol => Object}
Get capabilities supported by this backend
226 227 228 229 230 231 232 233 234 235 236 237 238 |
# File 'lib/tree_haver/backends/java.rb', line 226 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
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
# File 'lib/tree_haver/backends/java.rb', line 133 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_classes ⇒ Hash
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
216 217 218 |
# File 'lib/tree_haver/backends/java.rb', line 216 def java_classes @java_classes end |
.load_error ⇒ String?
Get the last load error message (for debugging)
208 209 210 |
# File 'lib/tree_haver/backends/java.rb', line 208 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)
177 178 179 180 181 182 183 |
# File 'lib/tree_haver/backends/java.rb', line 177 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_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.
Get the cached runtime library SymbolLookup
85 86 87 |
# File 'lib/tree_haver/backends/java.rb', line 85 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
92 93 94 |
# File 'lib/tree_haver/backends/java.rb', line 92 def runtime_lookup=(lookup) @runtime_lookup = lookup end |