-1

I have this method that only runs on Windows and uses classes from sun.awt.shell, however the application can run on non-windows systems, and on Java it can be used with the OpenSdk and I suspect this does not include the sun.awt.shell class.

I have removed sun.awt.shell import statements from the class so that the class name is only referenced in this method, and I can guarantee that this method will never actually be run on a non-windows machine.

But is this enough or will the class fail to load anyway on systems missing these classes, do I need to rewrite the method to use reflection ?

 public static boolean isRemote(String newPath)
    {
        try
        {
            Path root = Paths.get(newPath).getRoot();
            sun.awt.shell.ShellFolder shellFolder = sun.awt.shell.ShellFolder.getShellFolder(root.toFile());
            sun.awt.shell.ShellFolderColumnInfo[] cols = shellFolder.getFolderColumns();
            for (int i = 0; i < cols.length; i++)
            {
                if (cols[i].getTitle().equals(WINDOWS_SHELL_SIZE)
                        &&  ((String) shellFolder.getFolderColumnValue(i)).startsWith("Network Drive"))
                {
                    return true;
                }
                else if (cols[i].getTitle().equals(WINDOWS_SHELL_ATTRIBUTES)
                        &&  ((String) shellFolder.getFolderColumnValue(i)).startsWith("\\"))
                {
                    return true;
                }
            }
        }
        catch (Exception ex)
        {
            MainWindow.logger.log(Level.SEVERE, ex.getMessage(), ex);
            return false;
        }
        return false;
    }
Paul Taylor
  • 13,411
  • 42
  • 184
  • 351
  • why close, especially without a reason ! – Paul Taylor Sep 11 '17 at 11:01
  • "Will the class fail to load anyway on systems missing these classes [...]?" Well ... yes. In fact, your class will not fail to load. What will fail is a method call to `isRemote`. If the classes from package `sun.awt.shell` are not there at runtime, you will get a `NoClassDefFoundError`. This has nothing to do with the `import` statement which is a compile-time only feature. – Seelenvirtuose Sep 11 '17 at 11:10
  • Could you check, for example by `Class.forName("sun.awt.shell.ShellFolder")` and watch for `ClassNotFoundException` before using it ? – c0der Sep 11 '17 at 11:11
  • @Seelenvirtuose so the class will not fail to load, that is what I wanted to hear. there will never actually be a call to isremote() on a non-windows system so failure then is not a problem. – Paul Taylor Sep 11 '17 at 11:59

2 Answers2

0

But is this enough or will the class fail to load anyway on systems missing these classes.

If the classes are not present at runtime, then the program will fail. If you are using compiled-in references, you will typically get a NoClassDefFoundError during startup.

do I need to rewrite the method to use reflection ?

Reflection would not help. If you try to use Class.forName to load the class (for example) you will get a ClassNotFoundException if the class is not part of the JRE.


I don't fully understand what that code is actually doing, but it seems to be using mechanisms that simply wouldn't work on a Linux system (for example). Indeed, there isn't really a well-defined concept of a "remote" file on a Linux system.

Maybe it would help if you explained what you are using this method for. I suspect, it is something that only makes sense on Windows.

As a general rule, you should avoid using sun.* classes because: - they are often OS platform specific, and - they are liable to change, or be removed without notice.


I understand what you are asking now. You don't actually want1 isRemote to work on non-Windows systems.

There are a couple of alternatives:

  • You could split that method into two parts, and use dynamic class loading to load the system specific part. Or make the isRemote method a method in a dynamically loaded system specific plugin. (Basically the same idea ...) In either case, the dynamically loaded class can call ShellFolder using normal Java calls.

  • You could use Class.forName("sun.awt.shell.ShellFolder") to (attempt to) load the class and then use reflection to invoke methods on it.

However, my note about sun.* still stands. Sun / Oracle often do change or drop these internal classes.

1 - Or maybe you do, but you are resigned to the fact that it won't.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • You have misunderstood me I compile the code on windows and then it is deployed on Windows, OSX, Linux ectera. I know this method will not work in Linux its never going to be called on Linux is it for a particular task on Windows, but I dont want to have make adjustments in the build system just for this. But will the mere presence of this method in this class cause problems on a linux system which does not have the reference shell classes when the class is loaded into memory. – Paul Taylor Sep 11 '17 at 11:57
  • Yes . I did misunderstand you. – Stephen C Sep 11 '17 at 13:06
  • i am right to say that if I just move this isRemote() method into a new class that only contains this method. Then because the isRemote() is not ever called on some system the class will never be loaded and hence no problem. BTW I would much rather not uses these classes but it seems there is not a solution using only generic Java - https://stackoverflow.com/questions/46077551/in-java-how-do-i-find-actual-path-of-remote-filesystem-mounted-on-windows – Paul Taylor Sep 11 '17 at 16:21
  • I think so. Maybe. Test it. Re your BTW: my response would be why does a portable application *need* to find out the remote path ... given that it generally speaking is not a meaningful concept. – Stephen C Sep 12 '17 at 03:51
  • The issue is I want to know if a path is local or remote so I can give user option to not limit to 259 char path lengths when using against a remote drive. Portable application doesn't mean ignoring differences between different OSES. – Paul Taylor Sep 12 '17 at 06:23
  • Erm .... isn't it just simpler to show the user the error message that says that the path is too long ... when you get the exception? Like you would for other path "syntax" errors? – Stephen C Sep 12 '17 at 07:43
  • No, the application can mass rename thousands of files. The user may have a linux drive connected so they can use with the application but the files are not to be used on Windows therefore they dont want file naming to be subject to the Windows Explorer restriction (note its not an ntfs restriction) – Paul Taylor Sep 13 '17 at 09:41
0

The solution I went with was simply to put all the methods that required classes only available on Windows into one class. Then I before calling any of these methods form another class there was always a check to ensure running on the Windows OS

i.e

if(Platform.isWindows())
{
    return WindowsUtilsFS.isRemote(newPath)
}

so therefore the class never gets called or loaded. I have deployed this into Production and had no error reports so I think it is working correctly.

Paul Taylor
  • 13,411
  • 42
  • 184
  • 351