De la documentación para Field.set
:
Si el campo subyacente es definitiva, el método produce una IllegalAccessException
menos setAccessible(true)
ha tenido éxito para este campo y este campo es no estático.
Parece que no tiene suerte, ya que File.separatorChar
es static
. Sorprendentemente, hay es una forma de evitar esto: simplemente haga que el campo static
ya no sea final
a través de la reflexión.
que esta solución adaptada 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);
}
Lo he probado y funciona:
setFinalStatic(File.class.getField("separatorChar"), '#');
System.out.println(File.separatorChar); // prints "#"
Haz tenga mucho cuidado con esta técnica.consecuencias devastadoras aparte, la siguiente realmente funciona:
setFinalStatic(Boolean.class.getField("FALSE"), true);
System.out.format("Everything is %s", false); // "Everything is true"
Importante actualización: la solución anterior no se trabajo en todos los casos. Si el campo es accesible y se lee a través de Reflection antes de que se restablezca, se lanza un IllegalAccessException
. No funciona porque la API Reflection crea objetos internos FieldAccessor
que se almacenan en caché y se vuelven a utilizar (consulte la implementación de java.lang.reflect.Field # acquireFieldAccessor (boolean)). código de prueba que falle Ejemplo:
Field f = File.class.getField("separatorChar"); f.setAccessible(true); f.get(null);
// call setFinalStatic as before: throws IllegalAccessException
También podría ser mejor ejecutar las pruebas unitarias en un entorno VirtualBox bajo el otro sistema operativo objetivo. Quién sabe qué se romperá cuando te metas con la JVM así. Además, tal vez sea posible reescribir el código para no usar File.separatorChar directamente. Puede construir rutas usando el constructor File (parentFile, name), por ejemplo. – Thilo
@Thilo: Es una buena idea, y ahora que lo pienso, probablemente exista una manera de ejecutar mi lógica de forma multiplataforma sin tener que lidiar con las URL de los archivos en absoluto. Creo que saber cómo cambiar java.io.File.separatorChar, sin embargo, es útil para saber si hay algún otro caso de uso legítimo. –