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

有没有人知道JDK1.6和JDK1.7之间的拖放行为的差异? 将URL从浏览器拖放到需要支持JDK1.5,JDK1.6和JDK1.7的应用程序时,我遇到了不同(如下图所示)。 我现在想知道是否存在其他差异以及是否在某处记录了这些差异。

我遇到的不同行为是通过单击并拖动URL到Java应用程序来拖放来自浏览器(而不是来自地址栏但来自页面)的URL。 在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_list = ( List ) 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和文件列表数据的味道,并在transferable中提供它们。 然后,文件列表仅包含表示文件的URI。 因此,当只拖放URL时,文件列表为空。 我在JDK源代码中找不到这个,因为似乎transferable / transferdata是在本机代码中创建的(或者至少是我找不到源代码的代码)。 在OpenJDK邮件列表上有一个关于类似问题的讨论,包含以下引用

如果将文件列表从本机拖到Java中,则应用程序会同时看到URI列表和文件列表。 如果你在URI列表中拖动它会看到一个URI列表,如果所有URI都是文件也是非空文件列表,否则只是一个空文件列表。

EDIT2

根据serg.nechaev的答案,我在32/64位Linux系统和几个Windows系统(从XP到Windows7)上进行了一些测试。 在使用JDK7的Linux上,我总是获得URI dataflavor,并结合空文件列表的味道。 在Windows上,我获得了URI dataflavor和非空文件列表数据的味道。 似乎.URL文件是在temp目录中创建的,并且这也在文件列表数据风格中传递,而JDK 6则不是这样。

所有这些情况下的解决方案是首先检查URI dataflavor,并使用文件列表数据flavor作为后退

我认为导致此行为的更改是在$(JDK)/jre/lib/flavormap.properties中

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

但是,使用您的示例并从您的post拖动链接到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提交错误。