Java: use the clipboard to copy-paste Java objects between different instances of the same application

I am trying to implement copy-paste objects between different instances of the same application. Currently, it only works in one application (I mean copying and pasting in the same instance of the application), but it does not work between different instances.

Copy Code:

// MyObject is a class of objects I want to copy/paste; // MyObjectSelection is a class that impements Transferable and ClipboardOwner interfaces Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); MyObject data = new MyObject(selectedItems); MyObjectSelection dataSelection = new MyObjectSelection(data); clipboard.setContents(dataSelection, this); 

After that, I can check the contents of the clipboard, for example:

 Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); Transferable clipboardContent = clipboard.getContents(this); DataFlavor[] flavors = clipboardContent.getTransferDataFlavors(); System.out.println("flavors.length=" + flavors.length); for (int i = 0; i < flavors.length; i++){ System.out.println("flavor=" + flavors[i]); } 

If I do this from the same application instance that I copied the object, it works: flavors.length is 1 , mimetype application/x-java-serialized-object , and, well, it works.

But if I open the application, execute the copy, then I open the same application again (the first one does not close, that is, both instances start at the same time) and try to check the contents of the clipboard from there, then flavors.length is 0 .

I reviewed the documents and these examples: one , two , but I still can’t find what is wrong in my implementation.

Did I miss something?


UPD: I added sscce: clipboard_test.zip .

This is a test application (I use Eclipse to create it) with three source files:

  • ClipboardTest.java - the main class of the application
  • MyObject.java - a class for objects to copy / paste (this class contains only an array of String )
  • MyObjectSelection.java - a class that implements the Transerable and ClipboardOwner interfaces

    There are two buttons: "copy", "test".

    When you click the copy button, a new instance of MyObject is created and placed on the clipboard.

    When you press the test button, the contents of the clipboard are checked and the console echoes (the number of supported DataFlavor and each DataFlavor )

    So, repeat these steps:

  • Launch the application

  • Press the "copy" button: you will see the message "object copied" in the log
  • Press the "test" button: you will see the contents of the clipboard:

      flavors.length = 1 flavor[0] = java.awt.datatransfer.DataFlavor[mimetype=application/x-java-serialized-object;representationclass=MyObject] 
  • Launch another instance of the application (do not close the first)

  • Click the "test" button: you will see that the clipboard is empty:

      flavors.length = 0 

Why is this?


UPD2: sscce sent right here:

  import java.awt.BorderLayout; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.ClipboardOwner; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.Toolkit; import javax.swing.JButton; import javax.swing.SwingUtilities; import javax.swing.JFrame; public final class ClipboardTest implements Runnable, ClipboardOwner { public static void main(String[] args) { SwingUtilities.invokeLater (new ClipboardTest()); } public void run() { JFrame f = new JFrame ("Clipboard test"); f.setDefaultCloseOperation (JFrame.DISPOSE_ON_CLOSE); //-- Create "copy" button. // When you click it, new object "test_items" becomes created // and put to the clipboard. { JButton button_copy = new JButton("copy"); button_copy.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ String[] test_items = { "one", "two", "three" }; Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); MyObject data = new MyObject(test_items); MyObjectSelection dataSelection = new MyObjectSelection(data); clipboard.setContents(dataSelection, ClipboardTest.this); System.out.println("object copied"); } }); f.add(button_copy, BorderLayout.NORTH); } //-- Create "test" button. // When you click it, clipboard contents are checked // and echoed to the console (count of supported DataFlavor's, and each DataFlavor) { JButton button_test = new JButton("test"); button_test.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); Transferable clipboardContent = clipboard.getContents(this); DataFlavor[] flavors = clipboardContent.getTransferDataFlavors(); System.out.println("flavors.length = " + flavors.length); for (int i = 0; i < flavors.length; i++){ System.out.println("flavor[" + i + "] = " + flavors[i]); } } }); f.add(button_test, BorderLayout.SOUTH); } f.pack(); f.setVisible(true); } // ClipboardOwner implementation @Override public void lostOwnership(Clipboard clipboard, Transferable transferable){ System.out.println("ClipboardTest: Lost ownership"); } /* ***************************************************************************************** * Object that I want to copy/paste * ****************************************************************************************/ public static class MyObject { private String[] items; public MyObject(String[] items){ this.setItems(items); } public String[] getItems(){ return this.items; } public void setItems(String[] items){ this.items = items; } } public static class MyObjectSelection implements Transferable, ClipboardOwner { private static DataFlavor dmselFlavor = new DataFlavor(MyObject.class, "Test data flavor"); private MyObject selection; public MyObjectSelection(MyObject selection){ this.selection = selection; } // Transferable implementation @Override public DataFlavor[] getTransferDataFlavors(){ System.out.println("getTransferDataFlavors"); DataFlavor[] ret = {dmselFlavor}; return ret; } @Override public boolean isDataFlavorSupported(DataFlavor flavor){ return dmselFlavor.equals(flavor); } @Override public synchronized Object getTransferData (DataFlavor flavor) throws UnsupportedFlavorException { if (isDataFlavorSupported(flavor)){ return this.selection; } else { throw new UnsupportedFlavorException(dmselFlavor); } } // ClipboardOwner implementation @Override public void lostOwnership(Clipboard clipboard, Transferable transferable){ System.out.println("MyObjectSelection: Lost ownership"); } } } 
+6
source share
1 answer

Quote this tutorial :

Data transfer using this mechanism uses Object serialization, so the class that you use to transfer data must implement the Serializable interface, like everything that is serialized with it. If everything is not serializable, you will see a NotSerializableException during a drop or copy to the clipboard.

Your MyObject not Serializable , so it cannot work. This structure seems to detect this fact (in contrast to the situation with a non-aerializable subclass of a serializable parent class or similar scenarios in which non-serializability is detected only in the process), so it will not even offer this taste to other processes.

In general, two instances of the same Java application will not have the same address space, so they cannot just access another memory. Therefore, everything you pass must be serialized.

+5
source

All Articles