Using reflection to change static final File.separatorChar for unit testing?
Try invoking on an instance of file not on an instance of class File
E.g.
File file = ...;
field.setChar(file,'/');
You could also try http://code.google.com/p/jmockit/ and mock the static method FileSystem.getFileSystem(). (don't know if you can mock static variables, normally those hacks shouldn't be necessary -> write oo code and use 'only' mockito)
From the documentation for Field.set
:
If the underlying field is final, the method throws an
IllegalAccessException
unlesssetAccessible(true)
has succeeded for this field and this field is non-static.
So at first it seems that you are out of luck, since File.separatorChar
is static
. Surprisingly, there is a way to get around this: simply make the static
field no longer final
through reflection.
I adapted this solution from javaspecialist.eu:
static void setFinalStatic(Field field, Object newValue) throws Exception {
field.setAccessible(true);
// remove final modifier from field
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(null, newValue);
}
I've tested it and it works:
setFinalStatic(File.class.getField("separatorChar"), '#');
System.out.println(File.separatorChar); // prints "#"
Do exercise extreme caution with this technique. Devastating consequences aside, the following actually works:
setFinalStatic(Boolean.class.getField("FALSE"), true);
System.out.format("Everything is %s", false); // "Everything is true"
Important update: the above solution does not work in all cases. If the field is made accessible and read through Reflection before it gets reset, an IllegalAccessException
is thrown. It fails because the Reflection API creates internal FieldAccessor
objects which are cached and reused (see the java.lang.reflect.Field#acquireFieldAccessor(boolean) implementation).
Example test code which fails:
Field f = File.class.getField("separatorChar"); f.setAccessible(true); f.get(null);
// call setFinalStatic as before: throws IllegalAccessException