0

I downloaded a example of Drag and Drop in java between 2 JList, I'm using my own Objects, everything is working pretty fine, but I'm getting this Exception every time I drop an Object and don't know why.

java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to java.io.InputStream
    at sun.awt.datatransfer.DataTransferer.translateTransferable(DataTransferer.java:1372)
    at sun.lwawt.macosx.CDataTransferer.translateTransferable(CDataTransferer.java:131)
    at sun.awt.datatransfer.DataTransferer$6.run(DataTransferer.java:2380)
    at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:744)
    at java.awt.EventQueue.access$400(EventQueue.java:97)
    at java.awt.EventQueue$3.run(EventQueue.java:697)
    at java.awt.EventQueue$3.run(EventQueue.java:691)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:75)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:86)
    at java.awt.EventQueue$4.run(EventQueue.java:719)
    at java.awt.EventQueue$4.run(EventQueue.java:717)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:75)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:716)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)

this is the example I downloaded.

import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
import javax.activation.ActivationDataFlavor;
import javax.activation.DataHandler;
import javax.swing.DefaultListModel;
import javax.swing.JComponent;
import javax.swing.JList;
import javax.swing.TransferHandler;
import javax.swing.TransferHandler.TransferSupport;

class ListItemTransferHandler extends TransferHandler {

private final DataFlavor localObjectFlavor;
private JList source = null;
private int[] indices = null;
private int addIndex = -1; //Location where items were added
private int addCount = 0;  //Number of items added.

public ListItemTransferHandler() {
    super();
    localObjectFlavor = new ActivationDataFlavor(Object[].class, DataFlavor.javaJVMLocalObjectMimeType, "Array of items");
}

@Override
protected Transferable createTransferable(JComponent c) {
    source = (JList) c;
    indices = source.getSelectedIndices();
    java.util.List transferedObjects = source.getSelectedValuesList();
    return new DataHandler(transferedObjects.toArray(), localObjectFlavor.getMimeType());
}

@Override
public boolean canImport(TransferSupport info) {
    return info.isDrop() && info.isDataFlavorSupported(localObjectFlavor);
}

@Override
public int getSourceActions(JComponent c) {
    return MOVE; //TransferHandler.COPY_OR_MOVE;
}

@SuppressWarnings("unchecked")
@Override
public boolean importData(TransferSupport info) {
    if (!canImport(info)) {
        return false;
    }
    JList target = (JList) info.getComponent();
    JList.DropLocation dl = (JList.DropLocation) info.getDropLocation();
    DefaultListModel listModel = (DefaultListModel) target.getModel();
    int index = dl.getIndex();
    //boolean insert = dl.isInsert();
    int max = listModel.getSize();
    if (index < 0 || index > max) {
        index = max;
    }
    addIndex = index;
    try {
        Object[] values = (Object[]) info.getTransferable().getTransferData(localObjectFlavor);
        for (int i = 0; i < values.length; i++) {
            int idx = index++;
            listModel.add(idx, values[i]);
            target.addSelectionInterval(idx, idx);
        }
        addCount = source.equals(target) ? values.length : 0;
        return true;
    } catch (UnsupportedFlavorException ufe) {
        ufe.printStackTrace();
    } catch (IOException ioe) {
        ioe.printStackTrace();
    }
    return false;
}

@Override
protected void exportDone(JComponent c, Transferable data, int action) {
    cleanup(c, action == MOVE);
}

private void cleanup(JComponent c, boolean remove) {
    if (remove && indices != null) {
        //If we are moving items around in the same list, we
        //need to adjust the indices accordingly, since those
        //after the insertion point have moved.
        if (addCount > 0) {
            for (int i = 0; i < indices.length; i++) {
                if (indices[i] >= addIndex) {
                    indices[i] += addCount;
                }
            }
        }
        JList source = (JList) c;
        DefaultListModel model = (DefaultListModel) source.getModel();
        for (int i = indices.length - 1; i >= 0; i--) {
            model.remove(indices[i]);
        }
    }
    indices = null;
    addCount = 0;
    addIndex = -1;
 }
}

Main class

public class DragNdrop extends JPanel {
private DragNdrop() {
    super(new BorderLayout());
    JPanel p = new JPanel(new GridLayout(1,2,10,0));
    TransferHandler h = new ListItemTransferHandler();
    p.setBorder(BorderFactory.createTitledBorder("Drag & Drop between JLists"));
    p.add(new JScrollPane(makeList(h)));
    p.add(new JScrollPane(makeList(h)));
    add(p);
    setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    setPreferredSize(new Dimension(320, 240));
}

private static JList<Color> makeList(TransferHandler handler) {
    DefaultListModel<Color> listModel = new DefaultListModel<>();
    listModel.addElement(Color.RED);
    listModel.addElement(Color.BLUE);
    listModel.addElement(Color.GREEN);
    listModel.addElement(Color.CYAN);
    listModel.addElement(Color.ORANGE);
    listModel.addElement(Color.PINK);
    listModel.addElement(Color.MAGENTA);
    JList<Color> list = new JList<>(listModel);
    list.setCellRenderer(new DefaultListCellRenderer() {
        @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
            Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
            ((JLabel)c).setForeground((Color)value);
            return c;
        }
    });
    list.getSelectionModel().setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
    list.setDropMode(DropMode.INSERT);
    list.setDragEnabled(true);
    list.setTransferHandler(handler);
    return list;
}

public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        @Override public void run() {
            createAndShowGUI();
        }
    });
}
public static void createAndShowGUI() {
    try{
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    }catch(ClassNotFoundException | InstantiationException |
           IllegalAccessException | UnsupportedLookAndFeelException ex) {
        ex.printStackTrace();
    }
    JFrame frame = new JFrame("DnDBetweenLists");
    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    frame.getContentPane().add(new DragNdrop());
    frame.pack();
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
 }
}
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
  • 1
    I'd start by writing your own `DataFlavor` to support your object type and possibly your own `Transferable` – MadProgrammer Jul 03 '14 at 04:35
  • even when it works this way? Is there any example of custom DataFlavor and Transferable? Im not very used to this. thanks for your attention – Jose Miguel Ledón Jul 03 '14 at 04:42
  • 2
    As an [example](http://stackoverflow.com/questions/15531783/add-string-to-jlist-exactly-where-theyre-dropped-not-at-the-bottom/15536464#15536464) – MadProgrammer Jul 03 '14 at 04:48
  • Ok, will try with that, thanks – Jose Miguel Ledón Jul 03 '14 at 04:50
  • General tip: for better help sooner, post an [MCVE](http://stackoverflow.com/help/mcve) (Minimal Complete and Verifiable Example) like @MadProgrammer did in the linked answer. – Andrew Thompson Jul 03 '14 at 04:58
  • *"even when it works this way?"* but it's not. The problem seems to be the way that the `DataHandler` is translating the data back and forward... – MadProgrammer Jul 03 '14 at 05:01
  • BTW *`setPreferredSize(new Dimension(320, 240));`* See [Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?](http://stackoverflow.com/q/7229226/418556) (Yes.) A `JList` offers the `setVisibleRowCount(int)` method to control the height. – Andrew Thompson Jul 03 '14 at 05:13
  • I copied-and-pasted your code into my Eclipse, fixed some JDK version involed compiling errors, can run. It works. NO exception was found. – nicky_zs Jul 03 '14 at 05:38
  • really? What OS are you using? – Jose Miguel Ledón Jul 03 '14 at 06:44
  • @MadProgrammer I implemented your example and the Exception disappeared, but I don't know how to reject the cleanup from transferHandler. Sometimes I need to reject the drop acording to my bussiness rules. I return false in importData method, but the Object still disappears, how can I avoid it? – Jose Miguel Ledón Jul 03 '14 at 08:38

1 Answers1

1

I have a similar situation, with a JList whose ListModel contains instances of a custom class. I tried making the class Serializable but that didn't get rid of the ClassCastException. Eventually, I found a post from 2003 where the poster had identified the solution: you don't want to use just a bare MIME type from DataFlavor; you need to append ";class=".

https://lists.apple.com/archives/java-dev/2003/Apr/msg00458.html

Even though what's being transferred, in my case, is an array of objects:

SpecialObject[] myData...

the construction of ActivationDataFlavor looks like this:

new ActivationDataFlavor(SpecialObject[].class, "application/x-java-specialobject-array;class=com.foo.bar.baz.SpecialObject", "Array of SpecialObject")

Constructing the ActivationDataFlavor this way gets rid of the exception.

Stephen B.
  • 396
  • 2
  • 19