JDK1.6和JDK1.7之间的拖放差异

7
有人知道JDK1.6和JDK1.7之间的拖放行为差异吗?当我将URL从浏览器拖放到需要支持JDK1.5、JDK1.6和JDK1.7的应用程序时,我遇到了一个不同之处(如下所示)。我现在想知道是否存在其他差异以及它们是否有文档记录。
我遇到的不同行为是,当通过单击并拖动URL将其从浏览器(而不是地址栏)拖放到Java应用程序上时。在JDK1.6上,Transferable不支持DataFlavor.javaFileListFlavor,而在JDK1.7上支持(尽管在请求其传输数据时会得到空列表)。以下代码说明了问题。它打开一个JFrame,您可以在其中拖放像http://www.google.com这样的URL,并打印出它使用的是文件列表味还是URI列表味。
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.TransferHandler;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.List;

public class DragAndDropTester {
  private static DataFlavor URI_LIST_FLAVOR = null;

  static {
    try {
      URI_LIST_FLAVOR = new DataFlavor( "text/uri-list;class=java.lang.String" );
    }
    catch ( ClassNotFoundException ignore ) {
    }
  }
  public static void main( String[] args ) {
    try {
      EventQueue.invokeAndWait( new Runnable() {
        public void run() {

          JFrame testFrame = new JFrame( "Test" );

          JPanel contents = new JPanel( new BorderLayout() );
          contents.add( new JLabel( "TestLabel" ), BorderLayout.CENTER );

          contents.setTransferHandler( createTransferHandler() );

          testFrame.getContentPane().add( contents );
          testFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
          testFrame.setSize( 200, 200 );
          testFrame.setVisible( true );
        }
      } );
    } catch ( InterruptedException e ) {
      throw new RuntimeException( e );
    } catch ( InvocationTargetException e ) {
      throw new RuntimeException( e );
    }
  }

  private static TransferHandler createTransferHandler(){
    return new TransferHandler(  ){
      @Override
      public boolean importData( JComponent comp, Transferable aTransferable ) {
        try {
          if ( aTransferable.isDataFlavorSupported( DataFlavor.javaFileListFlavor ) ) {
            System.out.println("File list flavor");
            List<File> file_list = ( List<File> ) aTransferable.getTransferData( DataFlavor.javaFileListFlavor );
            System.out.println( "file_list = " + file_list );
          }
              if ( URI_LIST_FLAVOR != null && aTransferable.isDataFlavorSupported( URI_LIST_FLAVOR ) ){
            System.out.println("URI list flavor");
            String uri_list = ( String ) aTransferable.getTransferData( URI_LIST_FLAVOR );
            System.out.println( "uri_list = " + uri_list );
          }
        } catch ( UnsupportedFlavorException e ) {
          throw new RuntimeException( e );
        } catch ( IOException e ) {
          throw new RuntimeException( e );
        }
        return true;
      }

      @Override
      public boolean canImport( JComponent comp, DataFlavor[] transferFlavors ) {
        return true;
      }
    };
  }
}

在JDK 1.7.01上的输出结果

File list flavor
file_list = []
URI list flavor
uri_list = http://www.google.com

JDK1.6.0.18的结果输出

URI list flavor
uri_list = http://www.google.com

我可以轻易地为此问题创建一个解决方法,但我更感兴趣的是任何更多关于这些差异和/或文档方面的了解。 编辑 进一步的调查/搜索使我认为JDK7上的行为是创建URI和文件列表数据格式并在可传输对象中同时提供它们。然后,文件列表仅包含表示文件的URI。因此,当仅拖放URL时,文件列表为空。我无法在JDK源代码中找到这个问题,因为似乎可传输对象/传输数据是在本地代码(或至少我找不到源代码的代码)中创建的。OpenJDK邮件列表上有一个讨论类似问题,其中包含以下引用:

如果您从本地拖动文件列表到Java中,则应用程序会看到URI列表和文件列表。如果您拖入URI列表,则它会看到URI列表,如果所有URI都是文件,则还会看到非空文件列表,否则只会看到空文件列表。

编辑2

根据serg.nechaev的回答,我在32/64位Linux系统和几个Windows系统上进行了更多的测试(从XP到Windows7)。在JDK7上的Linux上,我总是得到URI数据格式,加上一个空文件列表数据格式。在Windows上,我得到了一个URI数据格式和一个非空的文件列表数据格式。似乎在临时目录中创建了一个.URL文件,并将其作为文件列表数据格式传递,而这在JDK 6中不是这种情况。

在所有这些情况下的解决方案是首先检查URI数据格式,然后使用文件列表数据格式作为备用。


1
Java 7 应该支持额外的功能。如果你在 Java 6 中可以做某些事情,在 Java 7 中不能做,那很可能是一个 bug。我会编写支持 Java 6 的代码,并且它也能在 Java 7 上运行。如果你说你想知道 Java 7 的每个新功能,以便决定是否使用该功能,那么你可能是第一个创建这样列表的人。你可能需要比较不同版本之间的源代码。顺便说一句,Java 6 更新 30 可能已经将一些 Java 7 的功能移植回来了。 - Peter Lawrey
嗯,正如输出中所看到的,它可以在Java6和Java7中都实现。然而,在Java 7中,我得到了一个文件列表,这破坏了我的应用程序中的代码,其中有一个if-else if-else结构,遍历所有的数据类型。所以现在它进入了代码中的文件列表分支,导致我的数据没有被导入,因为文件列表是空的。 - Robin
1个回答

2

我认为导致这种行为变化的是在$(JDK)/jre/lib/flavormap.properties文件中:

http://hg.openjdk.java.net/jdk7/hotspot-gc/jdk/diff/fd5bf5955e37/src/windows/lib/flavormap.properties

然而,使用您的示例并从您的帖子中将链接拖到Google上,在WinXP、FireFox 8上的JDK 1.7.0中,我同时获取文件列表和URI列表:

File list flavor
file_list = [C:\DOCUME~1\SERGN\LOCALS~1\Temp\httpwww.google.com.URL]
URI list flavor
uri_list = http://www.google.com/

这可能是JDK 1.7.01的特定平台错误,您可能需要进一步调查并向Oracle提交错误报告。


我还没有在WinXP上进行检查,但我会在今天进行测试,并让您知道是否存在相同的问题。 - Robin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接