Пользователям нашего программного обеспечения необходимо просматривать сетевые ресурсы в Windows 10 в нашем приложении Java Swing, однако JFileChooser Swing по умолчанию не имеет этой возможности.
В этом посте
Как перейти к сетевому узлу в JFileChooser?
Приличное решение представлено с использованием ShellFolder (sun private API) для установки текущего каталога JFileChooser, и мы использовали этот подход с некоторыми изменениями за последние пару лет без проблем.
public static File getNetworkShareFolder( final File folder ) throws IllegalArgumentException {
final File file = new NonCanonicalizingFile( folder.getPath() );
if( isNetworkShareFolder( file ) ) { // assume Win32ShellFolderManager2 will be present
try {
// JRE-13272 -PRIVATE API that must eventually be swapped for Java 9 alternative
// Using reflection because Win32ShellFolderManager2 may not exist in rt.jar on Linux build server
final Class win32ShellMgr = Class.forName( "sun.awt.shell.Win32ShellFolderManager2" );
// get static creation method from class, execute it
final Method cfMethod = win32ShellMgr.getMethod( "createShellFolder", File.class );
return (ShellFolder) cfMethod.invoke( win32ShellMgr.newInstance(), file );
} catch( final Exception xx ) {
xx.printStackTrace();
}
}
throw new IllegalArgumentException( "Given path is not a Windows network share folder." );
}
Однако мы переходим на Java 11, а в Java 9 и далее частные API-интерфейсы инкапсулируются, и нам было поручено больше их не использовать. Не беспокойтесь, API замены в OpenJDK вошли в FileSystemView, в подпакет Swing Filechooser.
sun.awt.shell.ShellFolder.isComputerNode (Файл) -> javax.swing.filechooser.FileSystemView.getFileSystemView (). IsComputerNode (Файл) sun.awt.shell.ShellFolder.getShellFolder (Файл) -> javax.swing .filechooser.FileSystemView.getFileSystemView (). getLinkLocation (File)
поэтому предыдущий код теперь становится
public static File getNetworkShareFolder( final File folder ) throws IllegalArgumentException {
final File file = new NonCanonicalizingFile( folder.getPath() );
if( isNetworkShareFolder( file ) ) {
try {
return FileSystemView.getFileSystemView().getLinkLocation( file );
} catch( final Exception xx ) {
xx.printStackTrace();
}
}
throw new IllegalArgumentException( "Given path is not a Windows network share folder." );
}
public static boolean isNetworkShareFolder( final File folder ) {
return FileSystemView.getFileSystemView().isComputerNode( new NonCanonicalizingFile( folder.getPath() ) );
}
Это было бы здорово, но, к сожалению, ОБА getShellFolder () и getLinkLocation () генерируют исключение под Java 11, которое не было сгенерировано под Java 8.
java.nio.file.InvalidPathException: UNC-путь отсутствует имя_ресурса:
\ 100.212.51.37 в
java.base / sun.nio.fs.WindowsPathParser.parse (WindowsPathParser.java:118)
в
java.base / sun.nio.fs.WindowsPathParser.parse (WindowsPathParser.java:77)
в java.base / sun.nio.fs.WindowsPath.parse (WindowsPath.java:92) в
java.base / sun.nio.fs.WindowsFileSystem.getPath (WindowsFileSystem.java:229)
в java.base / java.nio.file.Path.of (Path.java:147) в
java.base / java.nio.file.Paths.get (Paths.java:69) в
java.desktop / sun.awt.shell.ShellFolder.getShellFolder (ShellFolder.java:247)
в
java.desktop / javax.swing.filechooser.FileSystemView.getLinkLocation (FileSystemView.java:641)
Похоже, что теперь он считает UNC-пути недействительными, если у него нет действительного имени общего ресурса, то есть "\\ 100.212.51.37 \" недопустимо, но "\\ 100.212.51.37 \ myShare" в порядке.
Теперь, если вы получите папку оболочки для UNC-пути "\\ 100.212.51.37 \ myShare" и затем getParent (), вы получите папку оболочки для "\\ 100.212.51.37 \", которую мы хотели в первую очередь , К сожалению, этот обходной путь не подходит для наших клиентов из-за проблемы с курицей и яйцом - пользователи часто еще не знают ни одного из реальных имен общих ресурсов, это то, что они хотели просмотреть в первую очередь!
Argh - это хорошо работало в Java 8, но в Java 11, даже если вы нарушаете инкапсуляцию для использования оригинального частного API ShellFolder с помощью
'--add-exports', 'java.desktop/sun.awt.shell=ALL-UNNAMED'
Это не помогает, потому что предыдущее решение теперь выдает то же исключение в Java 11 (9+).
Другое решение, которое мы видели в StackOverflow, - это использование класса SmbFile в JCIFS , но из-за ограничений безопасности нам очень трудно использовать сторонний код. Особенно, если он не обновлен для Java 11 JPMS без использования частных API.
Интересно, что DirectoryChooser в JavaFX НЕ имеет этой проблемы. Если пользователь вручную вводит сетевой хост, он с удовольствием отобразит все имена общих ресурсов для этого хоста. Мы пойдем по этому пути, если придется, но иметь дело с модальностью между FX Stage над свинг-приложением - уродливо и потенциально очень много работы.
Все еще надеемся на более простой обходной путь, чтобы JFileChooser отображал сетевые ресурсы в Java 11 (Java 9+)! Может быть, кто-то знает хитрость, которую использует FX DirectoryChooser, и ее можно применить к JFileChooser?