Apache NetBeans version
Apache NetBeans 31
What happened
With the Breakpoints window open while a DAP debug session (ide/lsp.client's DAPDebugger) is stopped at a breakpoint, every repaint of the window logs a SEVERE ClassCastException and the status bar's error badge lights. The breakpoint rows still list, but the "breakpoint hit" icon is never painted.
The cause is a type disagreement between two classes in org.netbeans.modules.lsp.client.debugger (present on master, commit 4a51670, and on the release310 tag):
breakpoints/BreakpointModel.getIconBase(Object) calls
DAPStackTraceAnnotationHolder.contains(debugger.getCurrentLine(), breakpoint.getLine()) — DAPDebugger.getCurrentLine() returns a org.openide.text.Line.
DAPStackTraceAnnotationHolder.contains(Object currentLine, Line line) begins with
final Annotatable[] a = (Annotatable[]) currentLine; (line 102) — it expects the holder's annotation array, not a Line.
So whenever getCurrentLine() is non-null (any stopped DAP session) and the model paints a DAPLineBreakpoint row, the renderer throws. Expected: the row paints LINE_BREAKPOINT_PC when the current line is the breakpoint's line, and LINE_BREAKPOINT otherwise, with nothing logged.
A one-line fix either way: contains could accept a Line (compare currentLine.equals(line), plus the Line.Part case), or getIconBase could pass the holder's annotations instead of the debugger's current line.
SEVERE [global]
java.lang.ClassCastException: class org.openide.text.EditorSupportLineSet$SupportLine cannot be cast to class [Lorg.openide.text.Annotatable; (org.openide.text.EditorSupportLineSet$SupportLine and [Lorg.openide.text.Annotatable; are in unnamed module of loader org.netbeans.StandardModule$OneModuleClassLoader @66edbc51)
at org.netbeans.modules.lsp.client.debugger.DAPStackTraceAnnotationHolder.contains(DAPStackTraceAnnotationHolder.java:102)
at org.netbeans.modules.lsp.client.debugger.breakpoints.BreakpointModel.getIconBase(BreakpointModel.java:90)
at org.netbeans.spi.viewmodel.Models$DelegatingNodeModel.getIconBaseWithExtension(Models.java:3622)
at org.netbeans.spi.viewmodel.Models$CompoundModel.getIconBaseWithExtension(Models.java:4778)
at org.netbeans.modules.viewmodel.TreeModelNode.setModelIcon(TreeModelNode.java:889)
at org.netbeans.modules.viewmodel.TreeModelNode.getIcon(TreeModelNode.java:901)
at org.openide.explorer.view.NodeRenderDataProvider.getIcon(NodeRenderDataProvider.java:104)
at org.netbeans.swing.outline.DefaultOutlineCellRenderer.getTableCellRendererComponent(DefaultOutlineCellRenderer.java:314)
at org.openide.explorer.view.OutlineView$OutlineViewOutline$TranslatedTableCellRenderer.getTableCellRendererComponent(OutlineView.java:2297)
at org.netbeans.modules.viewmodel.DelegatingCellRenderer.getTableCellRendererComponent(DelegatingCellRenderer.java:66)
at org.openide.explorer.view.OutlineView$OutlineViewOutline$TranslatedTableCellRenderer.getTableCellRendererComponent(OutlineView.java:2297)
at java.desktop/javax.swing.JTable.prepareRenderer(JTable.java:5818)
at java.desktop/javax.swing.plaf.basic.BasicTableUI.paintCell(BasicTableUI.java:2187)
at java.desktop/javax.swing.plaf.basic.BasicTableUI.paintCells(BasicTableUI.java:2086)
Language / Project Type / NetBeans Component
NetBeans Platform application using the ide/lsp.client DAP debugger (org.netbeans.modules.lsp.client.debugger), JavaScript debugged through a DAP adapter (js-debug)
How to reproduce
- Any DAP-backed debugger using
org.netbeans.modules.lsp.client.debugger.api.DAPConfiguration (we use js-debug for Node; the adapter does not matter — the throw happens in the Breakpoints view's model).
- Set one line breakpoint via
DAPLineBreakpoint (gutter click / ⌘F8 on a JavaScript file).
- Open Window ▸ Debugging ▸ Breakpoints.
- Launch the debug session and let it stop at the breakpoint.
- Observe
messages.log: the ClassCastException above, repeated on every repaint of the Breakpoints window (8 times in a two-minute session); the status bar error badge lights; the row keeps the plain breakpoint icon rather than the "hit" icon.
Reading the two source files is enough to see it without running anything: BreakpointModel.getIconBase (lines 84–96 on master) passes debugger.getCurrentLine(), a Line, into DAPStackTraceAnnotationHolder.contains (line 100–102 on master), which casts its first argument to Annotatable[].
Did this work correctly in an earlier version?
No / Don't know
Operating System
macOS 27.0 (build 26A428), arm64
JDK
OpenJDK Runtime Environment Temurin-21.0.4+7 (build 21.0.4+7-LTS), Eclipse Adoptium, arm64
Apache NetBeans packaging
Apache NetBeans platform
Anything else
Every time, for any stopped DAP session, as long as the Breakpoints window is open. Found while working on NMOX Studio (a NetBeans Platform IDE built on RELEASE310); the analysis was made against the shipped bytecode first and then confirmed against the source on master.
Assisted-by: Claude Fable 5.1 (claude-fable-5-1) — investigation and report drafting; filed and reviewed by the reporter.
Are you willing to submit a pull request?
No
Apache NetBeans version
Apache NetBeans 31
What happened
With the Breakpoints window open while a DAP debug session (
ide/lsp.client'sDAPDebugger) is stopped at a breakpoint, every repaint of the window logs aSEVEREClassCastExceptionand the status bar's error badge lights. The breakpoint rows still list, but the "breakpoint hit" icon is never painted.The cause is a type disagreement between two classes in
org.netbeans.modules.lsp.client.debugger(present onmaster, commit 4a51670, and on therelease310tag):breakpoints/BreakpointModel.getIconBase(Object)callsDAPStackTraceAnnotationHolder.contains(debugger.getCurrentLine(), breakpoint.getLine())—DAPDebugger.getCurrentLine()returns aorg.openide.text.Line.DAPStackTraceAnnotationHolder.contains(Object currentLine, Line line)begins withfinal Annotatable[] a = (Annotatable[]) currentLine;(line 102) — it expects the holder's annotation array, not aLine.So whenever
getCurrentLine()is non-null (any stopped DAP session) and the model paints aDAPLineBreakpointrow, the renderer throws. Expected: the row paintsLINE_BREAKPOINT_PCwhen the current line is the breakpoint's line, andLINE_BREAKPOINTotherwise, with nothing logged.A one-line fix either way:
containscould accept aLine(comparecurrentLine.equals(line), plus theLine.Partcase), orgetIconBasecould pass the holder's annotations instead of the debugger's current line.Language / Project Type / NetBeans Component
NetBeans Platform application using the
ide/lsp.clientDAP debugger (org.netbeans.modules.lsp.client.debugger), JavaScript debugged through a DAP adapter (js-debug)How to reproduce
org.netbeans.modules.lsp.client.debugger.api.DAPConfiguration(we use js-debug for Node; the adapter does not matter — the throw happens in the Breakpoints view's model).DAPLineBreakpoint(gutter click / ⌘F8 on a JavaScript file).messages.log: theClassCastExceptionabove, repeated on every repaint of the Breakpoints window (8 times in a two-minute session); the status bar error badge lights; the row keeps the plain breakpoint icon rather than the "hit" icon.Reading the two source files is enough to see it without running anything:
BreakpointModel.getIconBase(lines 84–96 on master) passesdebugger.getCurrentLine(), aLine, intoDAPStackTraceAnnotationHolder.contains(line 100–102 on master), which casts its first argument toAnnotatable[].Did this work correctly in an earlier version?
No / Don't know
Operating System
macOS 27.0 (build 26A428), arm64
JDK
OpenJDK Runtime Environment Temurin-21.0.4+7 (build 21.0.4+7-LTS), Eclipse Adoptium, arm64
Apache NetBeans packaging
Apache NetBeans platform
Anything else
Every time, for any stopped DAP session, as long as the Breakpoints window is open. Found while working on NMOX Studio (a NetBeans Platform IDE built on RELEASE310); the analysis was made against the shipped bytecode first and then confirmed against the source on
master.Assisted-by: Claude Fable 5.1 (claude-fable-5-1) — investigation and report drafting; filed and reviewed by the reporter.
Are you willing to submit a pull request?
No