Skip to content

Launch AdminUI helper threads outside the constructor (CodeQL java/thread-start-in-constructor)#239

Open
vharseko wants to merge 2 commits into
OpenIdentityPlatform:masterfrom
vharseko:features/codeql-thread-start-ctor
Open

Launch AdminUI helper threads outside the constructor (CodeQL java/thread-start-in-constructor)#239
vharseko wants to merge 2 commits into
OpenIdentityPlatform:masterfrom
vharseko:features/codeql-thread-start-ctor

Conversation

@vharseko

@vharseko vharseko commented Jul 8, 2026

Copy link
Copy Markdown
Member

Summary

Resolves both java/thread-start-in-constructor alerts in AdminUI (lines 234
and 247). The AdminUI() constructor started two threads:

  • a frame-building thread (creates the JFrame/splash, then setupFrame()),
    joined before the constructor returned; and
  • a host-name lookup thread (InetAddress.getLocalHost()), fire-and-forget.

Both are anonymous Thread subclasses that capture this, so they could observe
AdminUI before its construction finished — the exact pattern the rule warns
about (most dangerous if the class is subclassed and a helper thread calls an
overridden method against uninitialised subclass state).

Change

The thread block is moved verbatim from the constructor into a new
public void launch() method, and main() calls it right after construction:

final AdminUI adminUI = new AdminUI(rmiHost);
adminUI.launch();
if (rmiHost != null) {
    adminUI.connect(rmiHost);
}

AdminUI is only ever instantiated by its own main() (verified across the
repo — the other UI classes just hold a reference handed to their setup(ui)
methods), so moving the launch out of the constructor affects no other caller.

Behaviour

The main() sequence is unchanged: construct (records the RMI host) → launch()
(builds the frame, waits for it, kicks off the host-name lookup) → connect().
The frame is still fully built before connect() runs, so the RMI connection and
window title behave exactly as before. The connect() call previously performed
inside the AdminUI(String) constructor now runs from main() after launch();
refresh() already guards _tabbedPane != null, so the remaining convenience
constructors stay safe.

Testing

mvn -o -pl persistit/ui compile — BUILD SUCCESS.

…read-start-in-constructor)

The AdminUI() constructor started two threads - one that builds the Swing frame
(joined before the constructor returned) and one that resolves the local host
name - so both anonymous Thread subclasses captured `this` and could touch
AdminUI fields before construction had finished (a hazard in particular if the
class were subclassed).

Move that block into a new public launch() method and have main() call it right
after constructing the instance, before connect(). AdminUI is only ever created
by its own main(), and the collaborator classes merely hold a reference passed to
their setup() methods, so no other caller is affected.

The main() flow is unchanged: construct (records the RMI host) -> launch (builds
the frame, waits for it, starts the host-name lookup) -> connect. The frame is
still fully built before connect() runs.
@vharseko vharseko requested a review from maximthomas July 8, 2026 14:18
@vharseko vharseko added codeql CodeQL static-analysis findings refactoring Code cleanup / refactoring, no behavior change labels Jul 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

codeql CodeQL static-analysis findings refactoring Code cleanup / refactoring, no behavior change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants