Para cerrar la brecha entre aioobe y las respuestas de Bozho, también aconsejaría no configurar el parámetro line.separator
en el arranque de JVM, ya que esto potencialmente rompe muchas suposiciones fundamentales que la JVM y el código de la biblioteca hacen sobre el entorno en el que se está ejecutando. Por ejemplo, si una biblioteca de la que depende se basa en line.separator
para almacenar un archivo de configuración de forma multiplataforma, acaba de romper ese comportamiento. Sí, es un caso extremo, pero eso lo hace aún más nefasto cuando, dentro de unos años, surge un problema, y ahora todo el código depende de que este ajuste esté en su lugar, mientras que sus bibliotecas lo están asumiendo (correctamente) no es
Dicho esto, a veces estas cosas están fuera de tu control, como cuando una biblioteca se basa en line.separator
y no proporciona ninguna manera de anular ese comportamiento explícitamente. En tal caso, está atascado anulando el valor, o algo más doloroso como volver a implementar o parchear el código manualmente.
Para aquellos casos limitados, el que es aceptable para anular line.separator
, pero tenemos que seguir dos reglas:
- minimizar el alcance de la anulación
- revertir la anulación no importa lo
Ambos requisitos están bien atendidos por AutoCloseable
y la sintaxis try-with-resources, así que he implementado una clase PropertiesModifier
que limpiamente proporciona ambos.
/**
* Class which enables temporary modifications to the System properties,
* via an AutoCloseable. Wrap the behavior that needs your modification
* in a try-with-resources block in order to have your properties
* apply only to code within that block. Generally, alternatives
* such as explicitly passing in the value you need, rather than pulling
* it from System.getProperties(), should be preferred to using this class.
*/
public class PropertiesModifier implements AutoCloseable {
private final String original;
public PropertiesModifier(String key, String value) {
this(ImmutableMap.of(key, value));
}
public PropertiesModifier(Map<String, String> map) {
StringWriter sw = new StringWriter();
try {
System.getProperties().store(sw, "");
} catch (IOException e) {
throw new AssertionError("Impossible with StringWriter", e);
}
original = sw.toString();
for(Map.Entry<String, String> e : map.entrySet()) {
System.setProperty(e.getKey(), e.getValue());
}
}
@Override
public void close() {
Properties set = new Properties();
try {
set.load(new StringReader(original));
} catch (IOException e) {
throw new AssertionError("Impossible with StringWriter", e);
}
System.setProperties(set);
}
}
Mi caso de uso estaba con Files.write()
, que es un método muy conveniente, salvo que se basa explícitamente en line.separator
. Envolviendo la llamada al Files.write()
puedo especificar claramente el separador de línea que quiero utilizar, sin arriesgarme a exponer esto a otras partes de mi aplicación (tome nota, por supuesto, de que esto todavía no es seguro para subprocesos).
try(PropertiesModifier pm = new PropertiesModifier("line.separator", "\n")) {
Files.write(file, ImmutableList.of(line), Charsets.UTF_8);
}
Puede probar \ r \ n –