Using reflection to change static final File.separatorChar for unit testing?
file-io, java, reflection, unit-testing
Solution
From the documentation for `Field.set`:
If the underlying field is final, the method throws an `IllegalAccessException` unless `setAccessible(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
Problem
Specifically, I'm trying to create a unit test for a method which requires uses `File.separatorChar` to build paths on windows and unix. The code must run on both platforms, and yet I get errors with JUnit when I attempt to change this static final field. Anyone have any idea what's going on? ``` Field field = java.io.File.class.getDeclaredField( "separatorChar" ); field.setAccessible(true); field.setChar(java.io.File.class,'/'); ``` When I do this, I get ``` IllegalAccessException: Can not set static final char field java.io.File.separatorChar to java.lang.Character ``` Thoughts?