NPE at Decorator.getOutermost(Decorator.java)

This bug

vassalengine.org/tracker/sho … gi?id=2377

was first reported 10 years ago. We seem to be getting more of them showing up across a number of modules. Eg. brand new ones vassalengine.org/tracker/sho … i?id=13206

The signature always looks like this:

java.lang.NullPointerException: null at VASSAL.counters.Decorator.getOutermost(Decorator.java:319) at VASSAL.command.ChangeTracker.<init>(ChangeTracker.java:35) at VASSAL.counters.PlaceMarker.placeMarker(PlaceMarker.java:209) at VASSAL.counters.Replace.replacePiece(Replace.java:55) at VASSAL.counters.Replace.myKeyEvent(Replace.java:48) at VASSAL.counters.Decorator.keyEvent(Decorator.java:299) at VASSAL.counters.Decorator.keyEvent(Decorator.java:300) at VASSAL.counters.KeyBuffer.keyCommand(KeyBuffer.java:119) at VASSAL.counters.KeyCommand.actionPerformed(KeyCommand.java:134) at java.desktop/javax.swing.AbstractButton.fireActionPerformed(Unknown Source)

PlaceMarker → ChangeTracker → Decorator.getOuterMost failing.

The code where this is failing is very simple:

public Command keyEvent(KeyStroke stroke) { Command c = myKeyEvent(stroke); return c == null ? piece.keyEvent(stroke) : c.append(piece.keyEvent(stroke)); // Failing on this line }

This bug desperately needs a friend.

Failing in “public static GamePiece VASSAL.counters.Decorator.getOutermost()” or in “public Command Decorator.keyEvent(KeyStroke stroke)”?

And yea my IDE already complains in PlaceMarker:

Probably needs to be fixed right there in PlaceMarker, if we handle the null case in Decorator.getOutermost() it will still throw NPE for parent.insert()

Yes, it is definitely a problem in PlaceMarker, nothing wrong with Decorator. Decorator.piece is the pointer to the next Decorator down the stack and should never be null except in the case of a raw prototype definition. in the bottom decorator on the stack, piece will point to the BasicPiece.

At this point in the code, the Marker being placed should be fully expanded with all Prototypes expanded out and replaced by their respective trait lists.

Something is going wrong in the creation of the marker to be placed.