GWT Server-side reflection - java

I am trying to use Reflection on the server side only of a GWT app. I have a basic example working in a non-GWT example which can be seen below.
package com.xyz.reflection;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class EntryPoint {
/**
* #param args
*/
public static void main(String[] args) {
ClassLoader dynClassLoader = ClassLoader.getSystemClassLoader();
Class<?> dynClass = null;
try {
dynClass = dynClassLoader.loadClass("com.xyz.reflection.RunMe");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Object dynInstance = null;
try {
dynInstance = dynClass.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
Method dynMethod = null;
try {
try {
dynMethod = dynInstance.getClass().getMethod("returnSid",
new Class[] { PassMe.class });
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
String returnValue = (String) dynMethod.invoke(dynInstance,
new Object[] { new PassMe() });
System.out.println("Return Value: " + returnValue.toString());
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
using the aptly named:
package com.xyz.reflection;
public class PassMe {
private String sid = "DEFAULT_SID";
public PassMe() {
this.sid = "INITIATED_SID";
}
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
}
and:
package com.xyz.reflection;
public class RunMe {
public String returnSid(PassMe s) {
return s.getSid();
}
}
This runs fine. When I try running this from a GWT server side class it doesn't work, and instead returns
java.lang.NoSuchMethodException: com.xyz.reflection.RunMe.returnSid(com.xyz.reflection.PassMe)
If I change the parameter to a String (instead of the 'PassMe' class) it works fine. Why does it not like passing my 'PassMe' class? I thought it might be an issue with serialization despite being 100% server code, but I haven't had any luck with this either.
Thanks in advance for any help anyone can give me with this.

In addition to finrod's solution, you can also change your class loader to something like:
ClassLoader dynClassLoader = PassMe.class.getClassLoader();
And you can use the PassMe.class style lookup again. The class used to find a loader doesn't seem to matter though. Just not the system loader.
Weird stuff. I wouldn't doubt if GWT is doing something weird with the class loader though.
Edit: Yep. GWT sets the system class loader to com.google.appengine.tools.development.IsolatedAppClassLoader in dev mode.

I think this could be related to Class loading - but it is just a hunch as I cannot experiment with it in context similar to yours.
Here are some suggestions to try:
You use:
ClassLoader dynClassLoader = ClassLoader.getSystemClassLoader();
dynClass = dynClassLoader.loadClass("com.xyz.reflection.RunMe");
To load the RunMe Class.
However to load the PassMe class you use:
PassMe.class
Try to load the PassMe Class through the dynClassLoader and use that instance in the getMethod() instead of the PassMe.class.
I wonder, do you need to use the dynClassLoader?

This is pretty much a shot in the dark, but does it help if you replace
dynMethod = dynInstance.getClass().getMethod("returnSid",
new Class[] { PassMe.class });
with
dynMethod = dynInstance.getClass().getMethod("returnSid", PassMe.class );
?
It doesn't make a difference outside of a GWT server, but it may exercise the container's VM differently.

Did you put your reflection file in the server side package?
For example:
org.myproject.client - your gwt client package (put here your java files that are able to be complied into java script NO REFLECTION)
org.myproject.server - put here any java files including reflection
org.myproject.shared - put here java classes that are able to be compiled into java script

Related

Java: check if a class exists and call a specific method if it exists

Is there a way to do the following? Check if a class exists (in the same package) and if it does exist, check if a particular method exists, and if so, calling it?
Say that I have class X. In some method of class X, I want to do the following:
if (class Y exists) { //Maybe use Class.forName("Y")?
if ( Y has method a(String, String) ) {
call Y.a("hello", "world");
}
}
Is such a thing possible? And is doing such a thing reasonable? Thanks.
Is such a thing possible? And is doing such a thing reasonable?
Thanks.
Of course it is possible.
If you develop a program or a library that has to discover dynamically some classes, it is a very reasonable thing.
If it is not the case, it could not be.
If your need makes sense, you should ask you an additional question : should you invoke a static or instance method ?
Here is a sample example with both solutions :
ReflectionClass that contains the logic using reflection :
import java.lang.reflect.Method;
public class ReflectionCalls {
public static void main(String[] args) {
new ReflectionCalls();
}
public ReflectionCalls() {
callMethod(true);
callMethod(false);
}
private void callMethod(boolean isInstanceMethod) {
String className = "DiscoveredClass";
String staticMethodName = "methodStatic";
String instanceMethodName = "methodInstance";
Class<?>[] formalParameters = { int.class, String.class };
Object[] effectiveParameters = new Object[] { 5, "hello" };
String packageName = getClass().getPackage().getName();
try {
Class<?> clazz = Class.forName(packageName + "." + className);
if (!isInstanceMethod) {
Method method = clazz.getMethod(staticMethodName, formalParameters);
method.invoke(null, effectiveParameters);
}
else {
Method method = clazz.getMethod(instanceMethodName, formalParameters);
Object newInstance = clazz.newInstance();
method.invoke(newInstance, effectiveParameters);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
DiscoveredClass (the class we manipulate in the example)
package reflectionexp;
public class DiscoveredClass {
public static void methodStatic(int x, String string) {
System.out.println("static method with " + x + " and " + string);
}
public void methodInstance(int x, String string) {
System.out.println("instance method with " + x + " and " + string);
}
}
Output :
instance method with 5 and hello
static method with 5 and hello
Yes, this can be done. I've created a Test class in the same Package as the current class.
import java.lang.reflect.Method;
public class Sample {
public static void main(String[] args) {
Class<?> clazz = null;
try {
clazz = Class.forName("Test");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (clazz == null) {
System.out.println("class not found. Go eat some waffles and correct the name");
return;
}
Method m = null;
try {
m = clazz.getMethod("foo", null);
} catch (NoSuchMethodException | SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (m == null) {
System.out.println("method not found. Go eat some waffles and correct the name");
return;
}
Test t;
try {
t = (Test) clazz.newInstance();
m.invoke(t, null);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class Test {
static {
System.out.println("test...");
}
public void foo() {
System.out.println("foo");
}
}
O/P :
test...
foo
You can use Class.forName:
try {
Class yourClass = Class.forName( "classname" );
Object o = yourClass.newInstance();
} catch( ClassNotFoundException e ) {
//Throw error or whatever
}
To check if a method exists you could use the NoSuchMethodError e in a try/catch
You can do this using reflection, however it isnt really practical unless you are trying to access classes that potentially will not be present at runtime or if you are trying to access private or hidden fields. Example below.
public static void reflectionDemo(){
//Here we attempt to get the common URI class
//If it is found, we attempt to get the create method
//We then invoke the create method and print the class name of the result.
try {
Class<?> uriClass = Class.forName("java.net.URI");
//getMethod(String name, Class<?>... args);
java.lang.reflect.Method create = uriClass.getMethod("create", String.class);
//The first parameter is null because this is a static method.
//invoke(Object target, Object... args);
System.out.println(create.invoke(null, "some/uri").getClass());
//Will print class java.net.URI
} catch (ClassNotFoundException e) {
// If class doesnt exist
e.printStackTrace();
} catch (NoSuchMethodException e) {
// If method doesnt exist
e.printStackTrace();
} catch (SecurityException e) {
// See Javadoc
e.printStackTrace();
} catch (IllegalAccessException e) {
// From invoke
e.printStackTrace();
} catch (IllegalArgumentException e) {
// From invoke
e.printStackTrace();
} catch (java.lang.reflect.InvocationTargetException e) {
// From invoke
e.printStackTrace();
}
}
To find whether a class exists, you can use the forName() method on Class.
To find whether a method exists, you can use the getMethod() method on Class.
Documentation here:
https://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#forName(java.lang.String)
https://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#getMethod(java.lang.String,%20java.lang.Class...)
For your class problem, you'd want to use code like:
try {
Class.forName("Y");
}
catch (ClassNotFoundException e) {
}
For your method problem, you'd want to use code like:
try {
Class.getMethod(a);
}
catch (NoSuchMethodException e) {
}
You can check if the Class exists with Class.forName("classname");
See this SO question: Check if class exists somewhere in package
If a method exists can be catched with NoSuchMethodError in your try/catch.
See this SO question: Check if method exists at Runtime in Java
try {
Object object = Class.forName("Y").newInstance();
object.a(String, String);
} catch( ClassNotFoundException | NoSuchMethodError ex) {
//do Something else
}

Can I pass parameters to my dynamically created classes?

I am successfully loading a class from an external MyClass.class file at runtime, and am able to call it's methods assuming I know the name of them, which I do.
The problem I'm having is I cannot figure out how to pass a parameter to the constructor of the class I am loading.
How can I modify this to pass a parameter to MyClass's constructor? Also, how can I access MyClass's public variable: infoToAccess?
Here are the files I'm working with. (Keep in mind, ClassLoaderExample.pde was written for Processing, but other than sketchPath("") and the lack of a main function, it is identical.
ClassLoaderExample.pde: The main file that loads the class:
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.MalformedURLException;
import java.lang.ClassLoader;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
/////// FILE STRUCTURE /////
// ClassLoaderExample //
// --this file //
// --tmp //
// ----MyClass.class //
////////////////////////////
// TODO
// Send parameter to MyClass constructor (by reference)
// Get public int number from MyClass
void setup()
{
String className = "MyClass";
Object instance;
Method updateMethod;
// sketchPath("") returns the directory this file is in
File file = new File(sketchPath(""));
try
{
URL url = file.toURL();
URL[] urls = new URL[]{url};
ClassLoader classLoader = new URLClassLoader(urls);
Class<?> loadedClass = classLoader.loadClass("tmp."+className);
try
{
instance = loadedClass.newInstance();
updateMethod = loadedClass.getDeclaredMethod("update");
// Calls MyClass's update() method
try
{
updateMethod.invoke(instance);
}
catch (InvocationTargetException e) {System.out.println(e);}
catch (IllegalAccessException e) {System.out.println(e);}
}
catch (InstantiationException e) {System.out.println(e);}
catch (IllegalAccessException e) {System.out.println(e);}
catch (NoSuchMethodException e) {System.out.println(e);}
}
catch (MalformedURLException e) {System.out.println(e);}
catch (ClassNotFoundException e) {System.out.println(e);}
}
MyClass.java: The class I am loading:
package tmp;
public class MyClass
{
public int infoToAccess = 1337;
public MyClass(int i)
{
System.out.println("MyClass constructor was called with numebr: " + i);
}
public void update()
{
System.out.println("Update was called.");
}
}
Thanks for any help with this!
you can use the class you loaded to get hold of the constructor
you need an use that to create a new instance.
import java.lang.reflect.Constructor;
...
Class<?> loadedClass = classLoader.loadClass("tmp."+className);
try {
Constructor<?> ctor=loadedClass.getConstructor(int.class);
ctor.newInstance(42);
...
}
...
You need to use reflection for both of the things you asked about:
Class<?> loadedClass = classLoader.loadClass("tmp." + className);
Object oInstance = null;
try {
Constructor<?> c = loadedClass.getConstructor(Integer.class);
oInstance = c.newInstance(10);
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
//Handle the possibility that you cannot access this constructor
}
To access the public field of your object:
try {
Field field = loadedClass.getField("infoToAccess");
int fieldValue = field.getInt(oInstance);
} catch (NoSuchFieldException | IllegalAccessException e) {
//Handle the possibility that you cannot access this field
}
As mentioned in the link I wrote in the comments, you can pass parameters in this call
updateMethod = loadedClass.getDeclaredMethod("update", parameters go here);
then you should be able to invoke the method with a parameter(s)
If you want to pass arguments to the constructor you cannot use getInstance(), you have to get the constructor object and pass the parameters there.
Example:
Constructor constructor = aClass.getConstructor(new Class[]{String.class});
MyObject myObject = (MyObject) constructor.newInstance("constructor-arg1");
See tutorial here: Java Reflection - Constructors

How to programmaticaly (java) obtain JBoss info and manage it?

Hi i want to obtain from java classes infos on JBoss like the status and the version and then manage him by starting/stopping/resatring him.
For the version i do this :
String fileSeparator = System.getProperty("file.separator");
String runJarFile = jbossHomeDir + fileSeparator + "bin" + fileSeparator + "run.jar";
System.out.println("JBOSSDIR est :" + runJarFile);
jarInputStream = new JarInputStream(new FileInputStream(runJarFile));
System.out.println("Pigmalion" + jarInputStream.getNextEntry().getName());
Manifest manifest = jarInputStream.getManifest();
Attributes attributes = manifest.getMainAttributes();
jbossVersion = attributes.getValue(Attributes.Name.SPECIFICATION_VERSION);
which works fine, now for the status, i saw some people doing it by checking the port, but isn't there another way of doing it ?
As for the start/stop/restart commands i saw this script
package com.sudipta.jboss.conf;
import org.jboss.Main;
public class JbossOperation {
public static Main ob;
static Class jbossMain;
static{
try {
jbossMain=Class.forName("org.jboss.Main");
ob = (Main)jbossMain.newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
/**
* START JBOSS SERVER
* #return true if started successfully
*/
public static boolean startServer(){
boolean status=true;
String str[]={"-c","default"};
try {
ob.boot(str);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return status;
}
/**
* STOP JBOSS SERVER
* #return true if started successfully
*/
public static boolean stopServer(){
boolean status=true;
try {
ob.shutdown();
} catch (Throwable e) {
e.printStackTrace();
}
return status;
}
/**
* Main method
* #param args
*/
public static void main(String args[]){
System.out.println("---------------------Strating the server------------------");
startServer();
System.out.println("---------------------Stoping the server------------------");
stopServer();
System.out.println("---------------------SERVER STOPPED------------------");
}
}
I downloaded the jboss-system 4.0.2 jar and it tells me the shutdown method doesn't exist. Do i have to download other jboss jars ?
If you are looking for something more enterprisy (but still open source). You may want to use RHQ for it. It allows to run operations on managed resources and it can start/restart/stop JBoss server, deploy a war to it and far more. But the learning curve may be quite steep.
Have you considered to use JMX Console?. Moreover, if you really need to manage the server from a Java program you could write a JMX client that invoke specific server operations like shutdown. Additionaly, different kind of server information can be obtained this way. (ofcourse JMX wont be useful for start the server).

How to test a Class.forName call in Java code?

I've been messing around with ClassLoaders in java recently, trying to test code which uses dynamic loading of classes (using Class.forName(String name)) with a custom ClassLoader.
I've got my own custom ClassLoader set up, which is supposed to be configurable to throw a ClassNotFoundException when trying to load a given class.
public class CustomTestClassLoader extends ClassLoader {
private static String[] notAllowed = new String[]{};
public static void setNotAllowed(String... nonAllowedClassNames) {
notAllowed = nonAllowedClassNames;
}
public static String[] getNotAllowed() {
return notAllowed;
}
public CustomTestClassLoader(ClassLoader parent){super(parent);}
#Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
for (String s : notAllowed) {
if (name.equals(s)) {
throw new ClassNotFoundException("Loading this class is not allowed for testing purposes.");
}
}
if(name.startsWith("java") || name.startsWith("sun") || getClass().getName().equals(name)) {
return getParent().loadClass(name);
}
Class<?> gotOne = super.findLoadedClass(name);
if (gotOne != null) {
return gotOne;
}
Class<?> c;
InputStream in = getParent().getResourceAsStream(name.replace('.', '/')+".class");
if (in == null) {
throw new ClassNotFoundException("Couldn't locate the classfile: "+name);
}
try {
byte[] classData = readBytes(in);
c = defineClass(name, classData, 0, classData.length);
} catch(IOException e) {
throw new ClassNotFoundException("Couldn't read the class data.", e);
} finally {
try {
in.close();
} catch (IOException e) {/* not much we can do at this point */}
}
if (resolve) {
resolveClass(c);
}
return c;
}
private byte[] readBytes(InputStream in) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buffer = new byte[4194304];
int read = in.read(buffer);
while (read != -1) {
out.write(buffer, 0, read);
read = in.read(buffer);
}
out.close();
return out.toByteArray();
}
}
I'm using -Djava.system.class.loader=com.classloadertest.test.CustomTestClassLoader to set this classloader as default ClassLoader.
I was hoping to be able to force a ClassNotFoundException by disallowing certain class names using CustomTestClassLoader.setNotAllowed(String...).
However, it only works for ClassLoader.loadClass, and not for Class.forName:
public void test() {
ClassLoader loader = this.getClass().getClassLoader();
CustomTestClassLoader custom = (CustomTestClassLoader)loader;
CustomTestClassLoader.setNotAllowed(NAME);
for (String s : custom.getNotAllowed())
System.out.println("notAllowed: "+s);
try {
System.out.println(Class.forName(NAME));
} catch (ClassNotFoundException e) {
System.out.println("forName(String) failed");
}
try {
System.out.println(Class.forName(NAME,false,custom));
} catch (ClassNotFoundException e) {
System.out.println("forName(String,boolean,ClassLoader) failed");
}
try {
System.out.println(custom.loadClass(NAME));
} catch (ClassNotFoundException e) {
System.out.println("ClassLoader.loadClass failed");
}
}
Now I expected all three try blocks to fail, since the documentation of Class.forName says it uses the ClassLoader of the caller (which should be custom/loader in this test).
However, only the final try block fails. Here is the output I get:
notAllowed: com.classloadertest.test.Test
class com.classloadertest.test.Test
class com.classloadertest.test.Test
ClassLoader.loadClass failed
Does Class.forName really use the classloader? And if so, which methods?
It seems to be using a native call, so I have no idea what it does under the covers.
Of course if anyone knows any alternative ways of testing a Class.forName() call, it would be much appreciated as well.
Class.forName() uses the classloader of the class where it is called from (e.g in your case the class that contains the test() method). So, if you are running it in a different environment this will cause the problem.
UPDATE That ClassLoader will be used in Class.forName() which loaded your Test class. And that may be the solution: It may be an Eclipse-defined classloader, that has access to your class, so it will load it. Despite that its parent (or root) classloaders have explicit rule to forbid the loading of that class.
I still recommend to make a wrapper class for this instantiation. You should load that class with your CustomTestClassLoader, then you can use Class.forName() in that class.

Find the directory for a FileStore

I'm trying to find a way to detect when a flash drive has been plugged into my computer. So far, the solution I found was to poll FileSystem#getFileStores for changes. This does indeed tell me when the flash drive has been inserted, but as far as I can tell there is no way to retrieve the location for it. FileStore#type and FileStore#name both seem highly unreliable as their return value is implementation specific, but they appear to be the only methods that might return any relevant information that might help find the directory for the FileStore.
With that in mind, the following code:
public class Test {
public static void main(String[] args) throws IOException {
for (FileStore store : FileSystems.getDefault().getFileStores()) {
System.out.println(store);
System.out.println("\t" + store.name());
System.out.println("\t" + store.type());
System.out.println();
}
}
}
Gave me this output:
/ (/dev/sda5)
/dev/sda5
ext4
/* snip */
/media/TI103426W0D (/dev/sda2)
/dev/sda2
fuseblk
/media/flashdrive (/dev/sdb1)
/dev/sdb1
vfat
As it turns out, FileStore#type returns the format of the drive and FileStore#name returns the location of the device file for the drive. As far as I can tell, the only method which has the location of the drive is the toString method, but extracting the path name out of it seems dangerous because I'm not sure how well that particular solution would hold up on other operating systems and future versions of Java.
Is there something I'm missing here or is this simply not possible purely with Java?
System Information:
$ java -version
java version "1.7.0_03"
OpenJDK Runtime Environment (IcedTea7 2.1.1pre) (7~u3-2.1.1~pre1-1ubuntu2)
OpenJDK Client VM (build 22.0-b10, mixed mode, sharing)
$ uname -a
Linux jeffrey-pc 3.2.0-24-generic-pae #37-Ubuntu SMP Wed Apr 25 10:47:59 UTC 2012 i686 athlon i386 GNU/Linux
Here's a temporary work around until a better solution is found:
public Path getRootPath(FileStore fs) throws IOException {
Path media = Paths.get("/media");
if (media.isAbsolute() && Files.exists(media)) { // Linux
try (DirectoryStream<Path> stream = Files.newDirectoryStream(media)) {
for (Path p : stream) {
if (Files.getFileStore(p).equals(fs)) {
return p;
}
}
}
} else { // Windows
IOException ex = null;
for (Path p : FileSystems.getDefault().getRootDirectories()) {
try {
if (Files.getFileStore(p).equals(fs)) {
return p;
}
} catch (IOException e) {
ex = e;
}
}
if (ex != null) {
throw ex;
}
}
return null;
}
As far as I know, this solution will only work for Windows and Linux systems.
You have to catch the IOException in the Windows loop because if there is no CD in the CD drive an exception is thrown when you try to retrieve the FileStore for it. This might happen before you iterate over every root.
This is what I have ended up doing. This is limited to Windows + UNIX but avoids using external tools or additional library calls. It steals the information Java already has in the FileStore objects
LinuxFileStore definitely extends UnixFileStore, so it will work. Same deal for Solaris. Since Mac OS X is UNIX, it probably works there but I'm not sure because I couldn't see its subclass in any place I was looking.
public class FileStoreHacks {
/**
* Stores the known hacks.
*/
private static final Map<Class<? extends FileStore>, Hacks> hacksMap;
static {
ImmutableMap.Builder<Class<? extends FileStore>, Hacks> builder =
ImmutableMap.builder();
try {
Class<? extends FileStore> fileStoreClass =
Class.forName("sun.nio.fs.WindowsFileStore")
.asSubclass(FileStore.class);
builder.put(fileStoreClass, new WindowsFileStoreHacks(fileStoreClass));
} catch (ClassNotFoundException e) {
// Probably not running on Windows.
}
try {
Class<? extends FileStore> fileStoreClass =
Class.forName("sun.nio.fs.UnixFileStore")
.asSubclass(FileStore.class);
builder.put(fileStoreClass, new UnixFileStoreHacks(fileStoreClass));
} catch (ClassNotFoundException e) {
// Probably not running on UNIX.
}
hacksMap = builder.build();
}
private FileStoreHacks() {
}
/**
* Gets the path from a file store. For some reason, NIO2 only has a method
* to go in the other direction.
*
* #param store the file store.
* #return the path.
*/
public static Path getPath(FileStore store) {
Hacks hacks = hacksMap.get(store.getClass());
if (hacks == null) {
return null;
} else {
return hacks.getPath(store);
}
}
private static interface Hacks {
Path getPath(FileStore store);
}
private static class WindowsFileStoreHacks implements Hacks {
private final Field field;
public WindowsFileStoreHacks(Class<?> fileStoreClass) {
try {
field = fileStoreClass.getDeclaredField("root");
field.setAccessible(true);
} catch (NoSuchFieldException e) {
throw new IllegalStateException("file field not found", e);
}
}
#Override
public Path getPath(FileStore store) {
try {
String root = (String) field.get(store);
return FileSystems.getDefault().getPath(root);
} catch (IllegalAccessException e) {
throw new IllegalStateException("Denied access", e);
}
}
}
private static class UnixFileStoreHacks implements Hacks {
private final Field field;
private UnixFileStoreHacks(Class<?> fileStoreClass) {
try {
field = fileStoreClass.getDeclaredField("file");
field.setAccessible(true);
} catch (NoSuchFieldException e) {
throw new IllegalStateException("file field not found", e);
}
}
#Override
public Path getPath(FileStore store) {
try {
return (Path) field.get(store);
} catch (IllegalAccessException e) {
throw new IllegalStateException("Denied access", e);
}
}
}
}
I've not really explored this area of java, but I found this, which seems to be related. It uses File.listRoots()
There also seems to be a number of related questions linked there too.
This works for Windows:
public Path getFileStoreRootPath(FileStore fs) throws Exception {
for (Path root : FileSystems.getDefault().getRootDirectories()) {
if (Files.isDirectory(root) && Files.getFileStore(root).equals(fs)) {
return root;
}
}
throw new RuntimeException("Root directory for filestore " + fs + " not found");
}
Basically, by filtering by condition Files.isDirectory(root) we are excluding all CD/DVD drives which will throw IOException when compact-disc is not inserted.

Categories