JDK-6759788 : Inability to fetch Transferable before acceptDrop breaks Swing DnD
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 6
  • Priority: P3
  • Status: Closed
  • Resolution: Won't Fix
  • OS: generic
  • CPU: generic
  • Submitted: 2008-10-15
  • Updated: 2019-12-17
  • Resolved: 2019-12-17
Description
It is completely acceptable to call getTransferable() and to inspect the Transferable contents in DropTargetListener.dragOver/dragEnter etc... to decide on the acceptability of the drag, before calling accept/rejectDrag.

ON THE CONTRARY, it is clearly documented that in DropTargetListener.drop, you MUST call acceptDrop before inspecting the Transferable contents.

So how can someone decide on the suitability of the Transferable contents BEFORE deciding whether to accept or reject the drop? They can't. And this breaks Swing drag and drop, which is supposed to allow that. Here's a test case. Drag a String from somewhere in a native app to the white area in the frame and then drop. An exception is printed to the console, with the first line:

InvalidDnDOperationException: No drop current

I've spoken with AWT.

For XDnD, Oleg says:
"After reading XDnD protocol I see no reasons to not allow to get data before accepting drop.  Perhaps Alexey knows some restrictions in Windows DnD.  Otherwise I'd say it is a bug."

For Windows, Alexey says:
"In accordance with native code analysis there is not any limitation in getting data without acceptDrop. Seems that described problem is an artifact of implementation that could be classified as bug."

import javax.swing.*;
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.event.*;
import java.io.*;

public class TranfailTest extends JFrame {
    
    JTextField tf = new JTextField();
    
    public TranfailTest() {
        tf.setTransferHandler(new MyTH());
        add(tf);
    }

    private static void createAndShowGUI(String[] args) {
        TranfailTest test = new TranfailTest();
        test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        test.setSize(400, 400);
        test.setVisible(true);
    }
    
    public static void main(final String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI(args);
            }
        });
    }

    class MyTH extends TransferHandler {
        public boolean canImport(TransferSupport support) {
            try {
                // here's the problem
                // canImport is called during drags AND before drop is accepted
                support.getTransferable().getTransferData(DataFlavor.stringFlavor);
            } catch (UnsupportedFlavorException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return true;
        }
    
        public boolean importData(TransferSupport support) {
            try {
                String str = (String)support.getTransferable().getTransferData(DataFlavor.stringFlavor);
                tf.setText(str);
            } catch (UnsupportedFlavorException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return true;
        }
    }
}