Modify ↓

Opened 10 minutes ago

Last modified 8 minutes ago

#25012 assigned defect

NullPointerException in ParallelWayAction.mouseDragged after JOSM loses focus mid-drag

Reported by: daredemodaisuki Owned by: wangi
Priority: normal Milestone:
Component: Core Version:
Keywords: template_report Cc:

Description (last modified by daredemodaisuki)

What steps will reproduce the problem?

  1. Switch to Parallel mode (Shift+P), select a way (or several ways forming a branchless path) and start dragging to create a parallel copy. Keep the left mouse button pressed and drag roughly halfway.
  2. Without releasing the button, switch to another window (e.g. trigger a screenshot tool by Win+Shift+S, or switch window by Win+tab) to let JOSM main window loss focus.
  3. Return to JOSM. The parallel-way preview stays frozen at the position where dragging was interrupted, and it no longer follows the mouse.
  4. Press and drag again.

What is the expected result?

The interrupted drag should be discarded: the tool should return to its normal (not dragging) state, the stale preview should disappear, and the next mouse press should start a clean operation. No exception should be thrown.

What happens instead?

A NullPointerException is thrown on the AWT event dispatch thread and JOSM reports an internal error. The parallel-way preview also stays visible and frozen, and a subsequent plain click may unexpectedly clear the selection instead of selecting a way.

Please provide any additional information below. Attach a screenshot if possible.

This may caused by "mode" and "pWays" out of sync.

Normally, the two fields "mode" and "pWays" must always be consistent (i.e. mode == Mode.DRAGGING implies pWays != null). But if JOSM loses focus when dragging:

  1. When the window loses focus during a drag, the mouseReleased event is never delivered, so mouseReleased() is not called. The action therefore stays in the "dragging" state forever: mode == Mode.DRAGGING, mouseIsDown == true, mouseHasBeenDragged == true, and pWays still points to the preview object.
  1. On the next mousePressed(MouseEvent), the existing pWays is discarded:

if (pWays != null && pWays.getWays() != null) {

... clearSelection(ways);
pWays = null;

}

but mode and mouseIsDown/mouseHasBeenDragged are not reset at this point. Normally this is masked because mouseReleased() resets them, but in this scenario mouseReleased() has already been lost.

  1. The subsequent mouseDragged(MouseEvent) passes the checks at the top of the method (mouseIsDown is still true, and the INITIAL_MOVE_DELAY of 200 ms has already elapsed), but the block "if (mode == Mode.NORMAL) { ... initParallelWays(...) }" is skipped because mode is still DRAGGING. Execution falls through to:

ParallelWays.ClosestPoint closest = pWays.closestPoint(enp); pWays == null

which throws:

java.lang.NullPointerException: Cannot invoke
"org.openstreetmap.josm.actions.mapmode.ParallelWays.closestPoint(org.openstreetmap.josm.data.coor.EastNorth)"
because "this.pWays" is null

at org.openstreetmap.josm.actions.mapmode.ParallelWayAction.mouseDragged(ParallelWayAction.java:407)

So the combination "mode == DRAGGING while pWays == null" is what triggers the crash. The same stale mouseHasBeenDragged flag is also why a plain click after returning to the window takes the "end of drag" branch of mouseReleased() and clears the source ways.

The screenshot tool is just one easy way to lose the mouseReleased event; alt-tabbing, a popup window stealing the button release, or a modal dialog appearing mid-drag should have the same effect.

It might be helpful to reset the whole drag state in mousePressed():

before starting a new press, discard any drag that did not end properly
mouseHasBeenDragged = false;
if (pWays != null) {

final List<Way> ways = new ArrayList<>(pWays.getWays());
ways.removeIf(w -> w.getDataSet() == null);
getLayerManager().getEditDataSet().clearSelection(ways);
pWays = null;
setMode(Mode.NORMAL); keep mode consistent with pWays == null
temporaryLayer.invalidate();
drop the stale preview

}

Or to validate the state at the start of mouseDragged():

if (!mouseIsDown)

return;

if (mode == Mode.DRAGGING && pWays == null) { previous drag did not end properly

setMode(Mode.NORMAL);
resetMouseTrackingState();
return;

}

Revision:19678
Build-Date:2026-11-05 12:52:25

Identification: JOSM/1.5 (19678 zh_CN) Windows 10 64-Bit
OS Build number: Windows 10 Home China 22H2 (19045)
Memory Usage: 352 MB / 11808 MB (94 MB allocated, but free)
Java version: 21.0.13+9-LTS, Azul Systems, Inc., OpenJDK 64-Bit Server VM
Look and Feel: com.sun.java.swing.plaf.windows.WindowsLookAndFeel
Screen: \Display0 1920x1080x32bpp@60Hz (scaling 1.00×1.00) \Display1 1080x1920x32bpp@60Hz (scaling 1.00×1.00)
Maximum Screen Size: 1920×1920
Best cursor sizes: 16×16→32×32, 32×32→32×32
System property file.encoding: UTF-8
System property sun.jnu.encoding: GBK
Locale info: zh_CN
Numbers with default locale: 1234567890 -> 1234567890
VM arguments: [-Djpackage.app-version=1.5.19678, -XX:MaxRAMPercentage=75.0, --add-modules=java.scripting,java.sql,javafx.controls,javafx.media,javafx.swing,javafx.web, --add-exports=java.base/sun.security.action=ALL-UNNAMED, --add-exports=java.desktop/com.sun.imageio.plugins.jpeg=ALL-UNNAMED, --add-exports=java.desktop/com.sun.imageio.spi=ALL-UNNAMED, --add-opens=java.base/java.lang=ALL-UNNAMED, --add-opens=java.base/java.nio=ALL-UNNAMED, --add-opens=java.base/jdk.internal.loader=ALL-UNNAMED, --add-opens=java.base/jdk.internal.ref=ALL-UNNAMED, --add-opens=java.desktop/javax.imageio.spi=ALL-UNNAMED, --add-opens=java.desktop/javax.swing.text.html=ALL-UNNAMED, --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED, -Djpackage.app-path=F:\ExternalAppData\JOSM\JOSM.exe]
Dataset consistency test: No problems found

Plugins:
+ BetterIME (1.2.0)
+ Columbina (1.0.4)
+ FastDraw (36503)
+ MaalausPRO (1.0.0)
+ MakeParallel (v1.1.0)
+ PicLayer (275)
+ RoadRailAlignment (0.2.3)
+ alignways (36493)
+ apache-commons (36483)
+ areaselector (372)
+ austriaaddresshelper (107)
+ buildings_tools (36503)
+ ejml (36483)
+ importvec (36504)
+ laplacian-smooth (4.9.1)
+ log4j (36483)
+ measurement (36503)
+ reverter (36503)
+ shrinkwrap (v1.1.3)
+ splinex (36483)
+ utilsplugin2 (36503)

Tagging presets:
+ https://github.com/OGFlab/name-suggestion-index/raw/main/dist/presets/nsi-josm-presets.xml
+ D:\地图和其它\OGF-Citō\OGF_hx_preset.xml

Map paint styles:
+ https://josm.openstreetmap.de/josmfile?page=Styles/MapWithAI&zip=1
+ https://josm.openstreetmap.de/josmfile?page=Styles/iD&zip=1

Last errors/warnings:
- 00017.077 E: 定位影像“mapmode/maalaus”时失败
- 00069.417 E: Handled by bug report queue: java.lang.NullPointerException: Cannot invoke "org.openstreetmap.josm.actions.mapmode.ParallelWays.closestPoint(org.openstreetmap.josm.data.coor.EastNorth)" because "this.pWays" is null
- 00069.422 E: Handled by bug report queue: java.lang.NullPointerException: Cannot invoke "org.openstreetmap.josm.actions.mapmode.ParallelWays.closestPoint(org.openstreetmap.josm.data.coor.EastNorth)" because "this.pWays" is null

OSM API: https://opengeofiction.net/api


=== REPORTED CRASH DATA ===
BugReportExceptionHandler#handleException:
No data collected.

Warning issued by: BugReportExceptionHandler#handleException

=== STACK TRACE ===
Thread: AWT-EventQueue-0 (40) of main
java.lang.NullPointerException: Cannot invoke "org.openstreetmap.josm.actions.mapmode.ParallelWays.closestPoint(org.openstreetmap.josm.data.coor.EastNorth)" because "this.pWays" is null
	at org.openstreetmap.josm.actions.mapmode.ParallelWayAction.mouseDragged(ParallelWayAction.java:407)
	at java.desktop/java.awt.AWTEventMulticaster.mouseDragged(Unknown Source)
	at java.desktop/java.awt.Component.processMouseMotionEvent(Unknown Source)
	at java.desktop/javax.swing.JComponent.processMouseMotionEvent(Unknown Source)
	at java.desktop/java.awt.Component.processEvent(Unknown Source)
	at java.desktop/java.awt.Container.processEvent(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Window.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
	at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
	at java.base/java.security.AccessController.doPrivileged(Unknown Source)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.desktop/java.awt.EventQueue$5.run(Unknown Source)
	at java.desktop/java.awt.EventQueue$5.run(Unknown Source)
	at java.base/java.security.AccessController.doPrivileged(Unknown Source)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.desktop/java.awt.EventQueue.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.run(Unknown Source)

Attachments (0)

Change History (1)

comment:1 by daredemodaisuki, 8 minutes ago

Description: modified (diff)

Modify Ticket

Change Properties
Set your email in Preferences
Action
as assigned The owner will remain wangi.
as The resolution will be set. Next status will be 'closed'.
to The owner will be changed from wangi to the specified user. Next status will be 'new'.
Next status will be 'needinfo'. The owner will be changed from wangi to daredemodaisuki.
as duplicate The resolution will be set to duplicate. Next status will be 'closed'. The specified ticket will be cross-referenced with this ticket.

Add Comment


E-mail address and name can be saved in the Preferences .
 
Note: See TracTickets for help on using tickets.