RFR: 4938801: The popup does not go when the component is removed [v6]
Prasanta Sadhukhan
psadhukhan at openjdk.org
Wed Jul 30 09:56:41 UTC 2025
On Wed, 30 Jul 2025 05:32:25 GMT, Jeremy Wood <duke at openjdk.org> wrote:
>> Hmm..We need to take a look at how to handle serialization aspect of propListener
>>
>> but as per https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html#serialization
>>
>>
>>> You can serialize a lambda expression if its target type and its captured arguments are serializable. However, like inner classes, the serialization of lambda expressions is strongly discouraged.
>
>>> You can serialize a lambda expression if its target type and its captured arguments are serializable
>
> I think that means `propListener` is NOT going to serialize, because `PropertyChangeListener` isn't `Serializable`. I'm unfamiliar with these details; I found this link helpful: https://www.baeldung.com/java-serialize-lambda
>
> Alternatively: if we put `propListener` in BasicPopupMenuUI: then I think serialization will be less of an issue. `JComponent#ui` is transient, so we don't try to serialize it (and all of its other listeners). This way the JPopupMenu will come out on the other side of deserialization using whatever the L&F is in that setup. This feels good-ish to me.
>
> (I'm assuming most L&F's extend BasicPopupMenuUI?)
>
> This is all just an idea/suggestion; as long as the deserialized JPopupMenu behaves like the original JPopupMenu I think that should be fine.
Yes, it seems deserialized JPopupMenu fails hiding the popup menu owing to `propListener` not getting serialized.
Tried with modified testcase of yours and fixed in latest PR
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.beans.PropertyChangeListener;
import java.io.*;
public class JPopupMenuSerializationTest {
public static class MyThread implements Runnable {
static Container box;
static Component invo;
public MyThread(Container cont, Component comp) {
this.invo = comp;
this.box = cont;
}
public void run() {
System.out.println("Starting 3 second countdown...");
try{
Thread.currentThread().sleep(3000);
} catch (Exception e) {}
System.out.println("Removing popup invoker from the container.");
box.remove(invo);
box.repaint();
}
}
public static void main(String[] args) throws Exception {
JPopupMenuSerializationTest test = new JPopupMenuSerializationTest();
test.testSerialization();
}
public void testSerialization() throws Exception {
JPopupMenu popupMenu = new JPopupMenu();
byte[] data = serialize(popupMenu);
JPopupMenu copy = deserialize(data);
test(copy);
}
private void test(JPopupMenu jpm) {
JFrame frame = new JFrame("My frame");
final Container pane = frame.getContentPane();
pane.setLayout(new BorderLayout());
pane.add(new JTextField("", 20), BorderLayout.NORTH);
JButton btn = new JButton("Exit");
final Thread[] thr = new Thread[] { null };
btn.setAction(new AbstractAction() {
public void actionPerformed(ActionEvent ev) {
System.exit(0);
}
});
btn.setText("Exit");
pane.add(btn, BorderLayout.SOUTH);
final JLabel label = new JLabel("Click here to invoke popup");
label.addMouseListener(new MouseAdapter() {
public void mouseReleased(MouseEvent e) {
jpm.add("One");
jpm.add("Two");
jpm.add("Three");
jpm.show(label,
label.getLocationOnScreen().x,
label.getLocationOnScreen().y);
}
public void mousePressed(MouseEvent e) {
Thread thr = new Thread(new MyThread(pane, label));
thr.start();
}
});
pane.add(label, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
private static byte[] serialize(JPopupMenu popupMenu) throws IOException {
try (ByteArrayOutputStream byteOut = new ByteArrayOutputStream()) {
try (ObjectOutputStream objOut = new ObjectOutputStream(byteOut)) {
objOut.writeObject(popupMenu);
}
return byteOut.toByteArray();
}
}
private static JPopupMenu deserialize(byte[] data) throws IOException, ClassNotFoundException {
try (ByteArrayInputStream byteIn = new ByteArrayInputStream(data)) {
try (ObjectInputStream objIn = new ObjectInputStream(byteIn)) {
return (JPopupMenu) objIn.readObject();
}
}
}
}
-------------
PR Review Comment: https://git.openjdk.org/jdk/pull/26407#discussion_r2242121247
More information about the client-libs-dev
mailing list