1

我正在为JTree. 我写了一个自定义TransferHandler并创建了一个新Transferable类。这门课很简单:

public class TreePathTransferable implements Transferable{

  private static final DataFlavor[] flavors = new DataFlavor[] {
          new DataFlavor(TreePath[].class,"TreePaths")};

  private TreePath[] data;

  public TreePathTransferable(TreePath[] data) {
    super();
    this.data = data;
  }

  public DataFlavor[] getTransferDataFlavors() {
    return flavors;
  }

  public boolean isDataFlavorSupported(DataFlavor flavor) {
    return flavors[0].equals(flavor);
  }

  public TreePath[] getTransferData(DataFlavor flavor) throws
          UnsupportedFlavorException, IOException{
    return data;
  }
}

如果“下降”我打电话

dtde.getTransferable().getTransferData(dtde.getTransferable().getTransferDataFlavors()[0])

我得到一个java.io.NotSerializableException. 如果我通过以下方式将数据对象的类更改TreePathTransferable为:Object

public class TreePathTransferable implements Transferable{

  private static final DataFlavor[] flavors = new DataFlavor[] {
          new DataFlavor(Object.class,"Object")};

  private Object data;

  public TreePathTransferable(Object data) {
    super();
    this.data = data;
  }

  public DataFlavor[] getTransferDataFlavors() {
    return flavors;
  }

  public boolean isDataFlavorSupported(DataFlavor flavor) {
    return flavors[0].equals(flavor);
  }

  public Object getTransferData(DataFlavor flavor) throws
          UnsupportedFlavorException, IOException{
    return data;
  }

}

一切正常。这对我来说毫无意义,因为传输的数据是相同的 - TreePath[]。为什么有区别?

堆栈跟踪

注意:我已经用 XXX 替换了不可序列化的类。这是 DefaultMutableTreeNode 子类的属性。这个子类是不可序列化的,所以Exception是有意义的,但是为什么她没有出现在第二种情况下呢?

java.io.NotSerializableException: XXX
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
    at java.util.HashMap.internalWriteEntries(HashMap.java:1777)
    at java.util.HashMap.writeObject(HashMap.java:1354)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:988)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1496)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
    at java.io.ObjectOutputStream.writeArray(ObjectOutputStream.java:1378)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1174)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
    at javax.swing.tree.DefaultMutableTreeNode.writeObject(DefaultMutableTreeNode.java:1287)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:988)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1496)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
    at java.io.ObjectOutputStream.writeArray(ObjectOutputStream.java:1378)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1174)
    at java.io.ObjectOutputStream.access$300(ObjectOutputStream.java:162)
    at java.io.ObjectOutputStream$PutFieldImpl.writeFields(ObjectOutputStream.java:1707)
    at java.io.ObjectOutputStream.writeFields(ObjectOutputStream.java:482)
    at java.util.Vector.writeObject(Vector.java:1077)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:988)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1496)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
    at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:441)
    at javax.swing.tree.DefaultMutableTreeNode.writeObject(DefaultMutableTreeNode.java:1278)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:988)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1496)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
    at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:441)
    at javax.swing.tree.DefaultMutableTreeNode.writeObject(DefaultMutableTreeNode.java:1278)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:988)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1496)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
    at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:441)
    at javax.swing.tree.DefaultMutableTreeNode.writeObject(DefaultMutableTreeNode.java:1278)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:988)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1496)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
    at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:441)
    at javax.swing.tree.DefaultMutableTreeNode.writeObject(DefaultMutableTreeNode.java:1278)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:988)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1496)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
    at java.io.ObjectOutputStream.writeArray(ObjectOutputStream.java:1378)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1174)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
    at sun.awt.datatransfer.TransferableProxy.getTransferData(TransferableProxy.java:83)
    at java.awt.dnd.DropTargetContext$TransferableProxy.getTransferData(DropTargetContext.java:376)

传输处理程序

public class MyTreeTransferHandler extends TransferHandler {
  public MyTreeTransferHandler() {
    super();
  }

  protected Transferable createTransferable(JComponent c) {
    Transferable t = null;
    if(c instanceof JTree) {
      JTree tree = (JTree) c;
        t = new TreePathTransferable(tree.getSelectionPaths());
        return t;
    }
    return t;
  }

  public int getSourceActions(JComponent c) {
    return TransferHandler.MOVE;
  }

  public boolean canImport(JComponent c, DataFlavor[] flavors){
    return true;
  }
}
4

1 回答 1

1

你的情况是由三件事引起的:

  1. 您在未直接指定不序列化传输数据的情况下使用了 DataFlavor 构造函数。无论如何它是间接的(参见DataFlavor.javaJVMLocalObjectMimeType或这个问题
  2. 如果可以,D&D 机制会尝试序列化传输的数据。原因是:“这隔离了共享 DnD 和剪贴板数据的应用程序”。
  3. D&D 机制通过检查您在 DataFlavor 构造函数中提供的类而不是传输对象的运行时类来检查它是否可以序列化数据。

在您的堆栈跟踪之后,这可以在TransferableProxy 源代码中看到:

public Object getTransferData(DataFlavor df)
        throws UnsupportedFlavorException, IOException
    {
        Object data = transferable.getTransferData(df);
        // If the data is a Serializable object, then create a new instance
        // before returning it. This insulates applications sharing DnD and
        // Clipboard data from each other.
        if (data != null && isLocal && df.isFlavorSerializedObjectType()) {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ClassLoaderObjectOutputStream oos =
                new ClassLoaderObjectOutputStream(baos);
            oos.writeObject(data);
            ByteArrayInputStream bais =
                new ByteArrayInputStream(baos.toByteArray());
            try {
                ClassLoaderObjectInputStream ois =
                    new ClassLoaderObjectInputStream(bais,
                                                     oos.getClassLoaderMap());
                data = ois.readObject();
            } catch (ClassNotFoundException cnfe) {

                throw (IOException)new IOException().initCause(cnfe);
            }
        }
        return data;
}

重要的部分是df.isFlavorSerializedObjectType()这调用 isRepresentationClassSerializable实现为的方法return java.io.Serializable.class.isAssignableFrom(representationClass);

因此,这会将您在DataFlavor构造函数中提供的类与Serializable接口进行比较。由于TreePath[].class 实现了 SerializableObject没有,因此不对Object类执行序列化(使用new DataFlavor(Object.class,"Object")构造函数调用)。

于 2019-09-12T10:03:15.717 回答