Reading Legacy Code: Java Interop
You will encounter these patterns in older BBj codebases. Each section shows the legacy approach and its modern equivalent.
Pre-use Fully-Qualified Class Names
You may see this in 3rd Gen (Early BBj) code:
rem Legacy: fully-qualified class names on every reference
map! = new java.util.HashMap()
list! = new java.util.ArrayList()
map!.put("key", "value")
iter! = map!.keySet().iterator()
while iter!.hasNext()
k! = iter!.next()
print k!, " = ", map!.get(k!)
wend
The modern equivalent:
rem Modern: use statements for clean short names
use java.util.HashMap
use java.util.ArrayList
map! = new HashMap()
list! = new ArrayList()
map!.put("key", "value")
iter! = map!.keySet().iterator()
while iter!.hasNext()
k! = iter!.next()
print k!, " = ", map!.get(k!)
wend
The use statement was added in later BBj versions to allow short class names. Before use, every reference to a Java class required the full package path. In large programs with dozens of Java class references, this made code significantly harder to read. Modern BBj places use statements at the top of the file, similar to import in Java.
ADDR() and CALL for Callbacks
You may see this in 2nd Gen (PRO/5) and 3rd Gen code:
rem Legacy: ADDR() for function pointer, CALL for invocation
rem ADDR() returns a "pointer" to a label or external program
addr_handler = addr("handler_routine")
rem CALL invokes a program/subroutine by name or address
call "MYHANDLER.bbj"
The modern equivalent:
rem Modern: setCallback with method reference in a Custom Object
use java.util.HashMap
class public MyApp
method public void run()
sysgui = unt
open(sysgui)"X0"
window! = BBjAPI().getSysGui().addWindow(10, 10, 300, 200, "App")
button! = window!.addButton(1, 50, 50, 100, 30, "Click")
button!.setCallback(BBjAPI.ON_BUTTON_PUSH, #this!, "onButtonPush")
process_events
methodend
method public void onButtonPush(BBjButtonPushEvent ev!)
a = msgbox("Button clicked!", 0, "Event")
methodend
classend
new MyApp().run()
ADDR() returned a numeric address for a label or subroutine, and CALL invoked programs by filename. This was the mechanism for inter-module communication before Custom Objects. Modern BBj uses setCallback with a method name string on an object reference, which provides type safety and keeps event handling within the class structure.
String-Based Data Exchange
You may see this in 2nd Gen and 3rd Gen code:
rem Legacy: pipe-delimited string as inter-module data transport
data$ = "Alice|Developer|Platform|2024"
rem Receiver parses with POS() and substring extraction
p1 = pos("|" = data$)
name$ = data$(1, p1 - 1)
rest$ = data$(p1 + 1)
p2 = pos("|" = rest$)
role$ = rest$(1, p2 - 1)
The modern equivalent:
rem Modern: pass a Java object between modules
use java.util.HashMap
map! = new HashMap()
map!.put("name", "Alice")
map!.put("role", "Developer")
map!.put("team", "Platform")
map!.put("year", "2024")
rem Receiver accesses fields by name
print map!.get("name")
print map!.get("role")
Before Java interop, programs exchanged data between modules using delimited strings (pipe |, comma, or SEP character CHR(254)) or fixed-width fields. The receiver had to know the exact format and parse it manually. Passing a HashMap or custom object provides named field access, eliminates parsing bugs, and makes the data contract explicit.
Procedural Java Interop
You may see this in 3rd Gen code:
rem Legacy: Java calls scattered throughout procedural code
rem No class structure, no encapsulation
map! = new java.util.HashMap()
map!.put("name", "Alice")
gosub process_data
release
process_data:
print "Name: ", map!.get("name")
rem More Java calls mixed with GOSUB logic
fmt! = new java.text.SimpleDateFormat("yyyy-MM-dd")
print "Date: ", fmt!.format(new java.util.Date())
return
The modern equivalent:
rem Modern: Java calls encapsulated in Custom Object methods
use java.util.HashMap
use java.text.SimpleDateFormat
use java.util.Date
class public DataProcessor
field private HashMap data!
method public DataProcessor(HashMap data!)
#data! = data!
methodend
method public void process()
print "Name: ", #data!.get("name")
fmt! = new SimpleDateFormat("yyyy-MM-dd")
print "Date: ", fmt!.format(new Date())
methodend
classend
map! = new HashMap()
map!.put("name", "Alice")
processor! = new DataProcessor(map!)
processor!.process()
Early BBj programs used Java objects but structured the code procedurally with labels and GOSUB. Java calls were scattered throughout the program without encapsulation. Modern BBj wraps Java interop in Custom Object methods, providing clear interfaces, reusable components, and the ability to extend Java classes or implement Java interfaces.