Skip to content

lsp.client: Breakpoints window throws ClassCastException on every repaint while a DAP session is stopped (BreakpointModel passes a Line where DAPStackTraceAnnotationHolder.contains casts to Annotatable[]) #9621

Description

@DavidLiedle

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

  1. 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).
  2. Set one line breakpoint via DAPLineBreakpoint (gutter click / ⌘F8 on a JavaScript file).
  3. Open Window ▸ Debugging ▸ Breakpoints.
  4. Launch the debug session and let it stop at the breakpoint.
  5. 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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    LSP[ci] enable Language Server Protocol tests

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions