Don't rely on an implicit default character set

JEP 400 (Java 18) will change the default character set to UTF-8
unconditionally.[1] Introduce SystemReader.getDefaultCharset() that
provides the locale-dependent charset the way JEP 400 recommends.

Change all code locations using Charset.defaultCharset() to use the
new SystemReader method instead.

[1] https://openjdk.java.net/jeps/400

Change-Id: I986f97a410d2fc70748b6f93228a2d45ff100b2c
Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
This commit is contained in:
Thomas Wolf 2021-09-03 19:49:27 +02:00 committed by Matthias Sohn
parent ff3c3d8ff5
commit fc6fe793ce
9 changed files with 54 additions and 17 deletions

View File

@ -19,7 +19,6 @@
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
@ -182,7 +181,7 @@ public void testReadPipePosixCommandFailure()
FS.readPipe(fs.userHome(),
new String[] { "/bin/sh", "-c", "exit 1" },
Charset.defaultCharset().name());
SystemReader.getInstance().getDefaultCharset().name());
}
@Test(expected = CommandFailedException.class)
@ -192,7 +191,7 @@ public void testReadPipeCommandStartFailure()
FS.readPipe(fs.userHome(),
new String[] { "this-command-does-not-exist" },
Charset.defaultCharset().name());
SystemReader.getInstance().getDefaultCharset().name());
}
@Test

View File

@ -440,6 +440,7 @@ lockOnNotHeld=Lock on {0} not held.
lockStreamClosed=Output to lock on {0} already closed
lockStreamMultiple=Output to lock on {0} already opened
logInconsistentFiletimeDiff={}: inconsistent duration from file timestamps on {}, {}: {} > {}, but diff = {}. Aborting measurement at resolution {}.
logInvalidDefaultCharset=System property "native.encoding" specifies unknown character set: {}
logLargerFiletimeDiff={}: inconsistent duration from file timestamps on {}, {}: diff = {} > {} (last good value). Aborting measurement.
logSmallerFiletime={}: got smaller file timestamp on {}, {}: {} < {}. Aborting measurement at resolution {}.
logXDGConfigHomeInvalid=Environment variable XDG_CONFIG_HOME contains an invalid path {}

View File

@ -12,13 +12,13 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.concurrent.Callable;
import org.eclipse.jgit.api.errors.AbortedByHookException;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.ProcessResult;
import org.eclipse.jgit.util.SystemReader;
import org.eclipse.jgit.util.io.TeeOutputStream;
/**
@ -171,7 +171,8 @@ protected void doRun() throws AbortedByHookException, IOException {
getStdinArgs());
if (result.isExecutedWithError()) {
handleError(new String(errorByteArray.toByteArray(),
Charset.defaultCharset().name()), result);
SystemReader.getInstance().getDefaultCharset().name()),
result);
}
}

View File

@ -468,6 +468,7 @@ public static JGitText get() {
/***/ public String lockStreamClosed;
/***/ public String lockStreamMultiple;
/***/ public String logInconsistentFiletimeDiff;
/***/ public String logInvalidDefaultCharset;
/***/ public String logLargerFiletimeDiff;
/***/ public String logSmallerFiletime;
/***/ public String logXDGConfigHomeInvalid;

View File

@ -23,7 +23,6 @@
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.charset.Charset;
import java.nio.file.AccessDeniedException;
import java.nio.file.FileStore;
import java.nio.file.Files;
@ -1507,7 +1506,7 @@ protected File discoverGitSystemConfig() {
try {
v = readPipe(gitExe.getParentFile(),
new String[] { gitExe.getPath(), "--version" }, //$NON-NLS-1$
Charset.defaultCharset().name());
SystemReader.getInstance().getDefaultCharset().name());
} catch (CommandFailedException e) {
LOG.warn(e.getMessage());
return null;
@ -1527,7 +1526,7 @@ protected File discoverGitSystemConfig() {
w = readPipe(gitExe.getParentFile(),
new String[] { gitExe.getPath(), "config", "--system", //$NON-NLS-1$ //$NON-NLS-2$
"--edit" }, //$NON-NLS-1$
Charset.defaultCharset().name(), env);
SystemReader.getInstance().getDefaultCharset().name(), env);
} catch (CommandFailedException e) {
LOG.warn(e.getMessage());
return null;

View File

@ -17,7 +17,6 @@
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.FileStore;
import java.nio.file.FileSystemException;
@ -119,8 +118,8 @@ private static int readUmask() {
new String[] { "sh", "-c", "umask" }, //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
null, null);
try (BufferedReader lineRead = new BufferedReader(
new InputStreamReader(p.getInputStream(), Charset
.defaultCharset().name()))) {
new InputStreamReader(p.getInputStream(), SystemReader
.getInstance().getDefaultCharset().name()))) {
if (p.waitFor() == 0) {
String s = lineRead.readLine();
if (s != null && s.matches("0?\\d{3}")) { //$NON-NLS-1$
@ -150,7 +149,8 @@ protected File discoverGitExe() {
try {
String w = readPipe(userHome(),
new String[]{"bash", "--login", "-c", "which git"}, // //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
Charset.defaultCharset().name());
SystemReader.getInstance().getDefaultCharset()
.name());
if (!StringUtils.isEmptyOrNull(w)) {
gitExe = new File(w);
}
@ -168,7 +168,8 @@ protected File discoverGitExe() {
try {
String w = readPipe(userHome(),
new String[] { "xcode-select", "-p" }, //$NON-NLS-1$ //$NON-NLS-2$
Charset.defaultCharset().name());
SystemReader.getInstance().getDefaultCharset()
.name());
if (StringUtils.isEmptyOrNull(w)) {
gitExe = null;
} else {

View File

@ -13,7 +13,6 @@
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.FileVisitOption;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
@ -150,8 +149,10 @@ protected File discoverGitExe() {
String w;
try {
w = readPipe(userHome(),
new String[]{"bash", "--login", "-c", "which git"}, // //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
Charset.defaultCharset().name());
new String[] { "bash", "--login", "-c", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
"which git" }, // //$NON-NLS-1$
SystemReader.getInstance().getDefaultCharset()
.name());
} catch (CommandFailedException e) {
LOG.warn(e.getMessage());
return null;

View File

@ -1160,7 +1160,7 @@ public static String decodeNoFallback(final Charset cs,
// Try the default character set. A small group of people
// might actually use the same (or very similar) locale.
Charset defcs = Charset.defaultCharset();
Charset defcs = SystemReader.getInstance().getDefaultCharset();
if (!defcs.equals(cs) && !defcs.equals(UTF_8)) {
try {
return decode(b, defcs);

View File

@ -17,6 +17,9 @@
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.UnsupportedCharsetException;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.nio.file.Paths;
@ -198,6 +201,8 @@ public static void setInstance(SystemReader newReader) {
private AtomicReference<FileBasedConfig> jgitConfig = new AtomicReference<>();
private volatile Charset defaultCharset;
private void init() {
// Creating ObjectChecker must be deferred. Unit tests change
// behavior of is{Windows,MacOS} in constructor of subclass.
@ -438,6 +443,35 @@ public Locale getLocale() {
return Locale.getDefault();
}
/**
* Retrieves the default {@link Charset} depending on the system locale.
*
* @return the {@link Charset}
* @since 6.0
* @see <a href="https://openjdk.java.net/jeps/400">JEP 400</a>
*/
public Charset getDefaultCharset() {
Charset result = defaultCharset;
if (result == null) {
// JEP 400: Java 18 populates this system property.
String encoding = getProperty("native.encoding"); //$NON-NLS-1$
try {
if (!StringUtils.isEmptyOrNull(encoding)) {
result = Charset.forName(encoding);
}
} catch (IllegalCharsetNameException
| UnsupportedCharsetException e) {
LOG.error(JGitText.get().logInvalidDefaultCharset, encoding);
}
if (result == null) {
// This is always UTF-8 on Java >= 18.
result = Charset.defaultCharset();
}
defaultCharset = result;
}
return result;
}
/**
* Returns a simple date format instance as specified by the given pattern.
*