Java Integration
The Java Interop Service provides runtime class information to the language server, enabling Java class completions and documentation.
Overview
BBj programs can use Java classes directly. To provide IDE support for this, the language server needs information about:
- Available Java classes
- Method signatures
- Field types
- Constructor parameters
- JavaDoc documentation
The Java Interop Service provides this information through reflection.
Architecture
┌──────────────────────┐ JSON-RPC ┌──────────────────────┐
│ Language Server │◄────────Port 5008────────►│ Java Interop Service │
│ (TypeScript) │ │ (Java) │
└──────────────────────┘ └──────────────────────┘
│ │
│ │
┌────▼────┐ ┌─────────▼─────────┐
│ BBj AST │ │ Class Loader │
│ │ │ │
│ use │ │ ┌─────────────┐ │
│ java.* │ │ │ BBj JARs │ │
│ │ │ │ Java RT │ │
└─────────┘ │ │ Custom JARs │ │
│ └─────────────┘ │
└───────────────────┘
Communication Protocol
Transport
- Protocol: JSON-RPC 2.0
- Port: 5008 (default)
- Library: LSP4J JSON-RPC
Request/Response Format
// Request
{
"jsonrpc": "2.0",
"id": 1,
"method": "getClassInfo",
"params": {
"className": "java.util.ArrayList"
}
}
// Response
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"name": "ArrayList",
"package": "java.util",
"methods": [...],
"fields": [...],
"constructors": [...]
}
}
RPC Methods
getTopLevelPackages()
Returns all top-level Java packages available in the classpath.
Response:
{
"packages": ["java", "javax", "com", "org", "bbj"]
}
getClassInfos(PackageInfoParams)
Returns all classes in a specific package.
Parameters:
{
"packageName": "java.util"
}
Response:
{
"classes": [
{ "name": "ArrayList", "isInterface": false },
{ "name": "List", "isInterface": true },
...
]
}
getClassInfo(ClassInfoParams)
Returns detailed information about a specific class.
Parameters:
{
"className": "java.util.ArrayList"
}
Response:
{
"name": "ArrayList",
"package": "java.util",
"superClass": "java.util.AbstractList",
"interfaces": ["java.util.List", "java.io.Serializable"],
"methods": [
{
"name": "add",
"returnType": "boolean",
"parameters": [
{ "name": "element", "type": "E" }
],
"modifiers": ["public"]
}
],
"fields": [...],
"constructors": [...]
}
loadClasspath(ClassPathInfoParams)
Loads additional JARs into the classpath.
Parameters:
{
"entries": ["/path/to/custom.jar"]
}
Java Implementation
Main Entry Point
SocketServiceApp.java:
public class SocketServiceApp {
public static void main(String[] args) {
ServerSocket serverSocket = new ServerSocket(5008);
while (true) {
Socket client = serverSocket.accept();
// Handle connection with LSP4J JSON-RPC
}
}
}
Service Implementation
InteropService.java implements the core reflection logic:
public class InteropService {
@JsonRequest
public ClassInfo getClassInfo(ClassInfoParams params) {
Class<?> clazz = Class.forName(params.getClassName());
return extractClassInfo(clazz);
}
private ClassInfo extractClassInfo(Class<?> clazz) {
// Use reflection to build ClassInfo
Method[] methods = clazz.getMethods();
Field[] fields = clazz.getFields();
// ...
}
}
Custom Class Loader
BbjClassLoader.java manages classpath:
public class BbjClassLoader extends URLClassLoader {
public void addClasspathEntry(String path) {
addURL(new File(path).toURI().toURL());
}
}
Data Models
ClassInfo
public class ClassInfo {
String name;
String packageName;
String superClass;
List<String> interfaces;
List<MethodInfo> methods;
List<FieldInfo> fields;
List<MethodInfo> constructors;
boolean isInterface;
boolean isAbstract;
}
MethodInfo
public class MethodInfo {
String name;
String returnType;
List<ParameterInfo> parameters;
List<String> modifiers;
String javadoc;
}
FieldInfo
public class FieldInfo {
String name;
String type;
List<String> modifiers;
}
Classpath Management
Default Classpath
The service automatically loads:
- BBj Runtime: Classes from
$BBJ_HOME/lib/ - Java Runtime: Standard Java classes
- BBj Add-ons: Additional BBj libraries
BBj Version Detection
The service detects BBj version to find libraries:
// BBj 24+: .lib directory
// Earlier: lib directory
String libDir = bbjVersion >= 24 ? ".lib" : "lib";
Custom Entries
Additional JARs can be loaded via:
- Configuration in Enterprise Manager
- Direct
loadClasspathRPC call - Workspace configuration
TypeScript Integration
Client Implementation
java-interop.ts provides the TypeScript interface:
export class JavaInteropService {
private connection: MessageConnection;
async getClassInfo(className: string): Promise<ClassInfo> {
return this.connection.sendRequest('getClassInfo', { className });
}
async getCompletions(prefix: string): Promise<CompletionItem[]> {
const classes = await this.getClassesForPrefix(prefix);
return classes.map(c => this.toCompletionItem(c));
}
}
Caching
Class information is cached to improve performance:
private classCache = new Map<string, ClassInfo>();
async getClassInfo(className: string): Promise<ClassInfo> {
if (this.classCache.has(className)) {
return this.classCache.get(className)!;
}
const info = await this.fetchClassInfo(className);
this.classCache.set(className, info);
return info;
}
Starting the Service
Automatic Start
The VS Code extension starts the service automatically when needed.
Manual Start
cd java-interop
./gradlew run
Build JAR
./gradlew build
# Output: build/libs/java-interop.jar
Troubleshooting
Service Not Responding
- Check if port 5008 is available
- Verify Java 17+ is installed
- Check BBj home configuration
Missing Classes
- Verify classpath configuration
- Check JAR files exist
- Look for class loading errors in logs
Performance Issues
- Large classpaths may slow startup
- Consider caching warm-up
- Check network latency if remote