Enhanced fork of javalang — fixes core AST bugs, adds Java 9-22 syntax support, zero external dependencies.
pip install ljavalangThe package name is ljavalang on PyPI, but the import name remains javalang — fully compatible with upstream.
>>> import javalang
>>> tree = javalang.parse.parse('package com.example; class Test {}')
>>> tree.package.name
'com.example'
>>> tree.types[0].name
'Test'Java 14 switch expression:
>>> code = '''
... class T {
... int m(int x) {
... return switch(x) {
... case 1 -> 10;
... case 2 -> 20;
... default -> 0;
... };
... }
... }'''
>>> tree = javalang.parse.parse(code)
>>> tree.types[0].body[0].body[0].expression
SwitchExpressionJava 16 record:
>>> tree = javalang.parse.parse('record Point(int x, int y) {}')
>>> tree.types[0]
RecordDeclarationJava 21 record pattern:
>>> code = '''
... class T {
... record Point(int x, int y) {}
... void m(Object o) {
... switch(o) {
... case Point(int x, int y) -> System.out.println(x + y);
... default -> {}
... }
... }
... }'''
>>> javalang.parse.parse(code) # parses successfullyChained method calls (core bug fix):
>>> code = 'class T { void m(String cmd) { Runtime.getRuntime().exec(cmd); } }'
>>> tree = javalang.parse.parse(code)
>>> # Upstream incorrectly places exec in a flat selectors list
>>> # Ljavalang correctly builds nested MethodInvocation qualifier chainfrom javalang.visitor import JavaVisitor
class MethodCollector(JavaVisitor):
def __init__(self):
self.methods = []
def visit_MethodDeclaration(self, node):
self.methods.append(node.name)
self.generic_visit(node)
collector = MethodCollector()
collector.visit(tree)
print(collector.methods) # ['foo', 'bar', ...]from javalang.tokenizer import tokenize
code = 'int x = 42;'
for token in tokenize(code):
r = token.position.range
print(f'{token.value} -> code[{r.start}:{r.stop}] = {code[r]!r}')
# int -> code[0:3] = 'int'
# x -> code[4:5] = 'x'>>> code = 'class T { void m() { try { int x = 1; } catch (Exception e) {} } }'
>>> tree = javalang.parse.parse(code)
>>> tree.types[0].end_position
Position(line=1, column=66, range=slice(65, 66, None))Full list (click to expand)
- Lambda expressions
- Method references
- Type annotations
- Interface default/static methods
- Generic try-with-resources
- Receiver parameter (
Inner.this)
- try-with-resources with effectively final variables
- module-info.java (module / open module / requires / exports / opens / uses / provides)
- Interface private methods
- Anonymous class diamond operator
varlocal variable type inferencevarin for-each / try-with-resourcesvarin lambda parameters
- Switch expression (
case X ->arrow syntax) - Switch expression at expression level (
return switch(...)) - Multi-label case (
case 1, 2, 3 ->) yieldstatement- Pattern matching
instanceof(obj instanceof String s)
- Text block (
"""..."""triple-quoted strings)
recordclass declaration- Local record / enum (inside method body)
- Record as class member
sealedclass / interfacepermitsclausenon-sealedmodifier
- Pattern matching switch (
case String s ->) - Record pattern deconstruction (
case Point(int x, int y) ->) - Nested record patterns
case nullmatching
- Unnamed variable
_ - Unnamed lambda parameters
| Category | Details |
|---|---|
| Core bug fix | Chained method calls now produce nested MethodInvocation qualifier chains instead of flat selectors lists |
| Bug fixes | 6 upstream bugs fixed: #90/#117 (DecimalInteger), #145 (Character token), #81/#112 (type annotations), #141 (void return_type) |
| New features | end_position for 6 AST nodes, Visitor class, Position.range, tokenize return_index, ReceiverParameter, prefix/postfix operators |
| Dependencies | Zero external dependencies (removed six) |
| Packaging | Modern pyproject.toml (PEP 621), setuptools ≥64.0 |
| Tests | 112 pytest tests (Python 3.9-3.12 CI matrix) |
Ljavalang/
├── pyproject.toml # Packaging (PEP 621)
├── javalang/
│ ├── parse.py # Entry: parse() / parse_expression()
│ ├── parser.py # Recursive descent parser (~2800 lines)
│ ├── tokenizer.py # Lexer (~700 lines)
│ ├── tree.py # AST node definitions (~340 lines)
│ ├── visitor.py # Visitor pattern traversal
│ └── test/ # 112 test cases
└── docs/
├── changelog.md
└── architecture.md
Based on c2nes/javalang by Chris Thunes.
MIT License