Eclipseでのfile.encodingの勝手な設定

問題点

10年ほどメンテナンスを続けているJavaプログラムのソースがShift_JISだったので、すべてのソースコードをUTF-8に変換し、それを最新のEclipse Oxygenに載せる。
OxygenではデフォルトのエンコーディングがUTF-8になっているようで、そのまま動作する。。。はずだったが、外部プロセスを起動し、その出力を見てみると化けている。

原因

調べてみると、Eclipseが勝手にfile.encodingを設定することがわかった。例えば以下の簡単なコードを実行してみる。

public class Main {
  public static void main(String[]args) {
    System.out.println("" + System.getProperty("file.encoding"));
  }
}

日本語は一切含まれないので、プロジェクトのText file encodingをUTF-8, MS932と変更して実行してみると、

  • UTF-8のときは「UTF-8」と出力される。
  • MS932のときは「MS932」と出力される。

つまり、プロジェクトのText file encodingを変更すると、Eclipse上での実行の時に勝手にVMに「-Dfile.encoding=***」が指定されるらしい。

jarにした場合

しかし、当然ながら、このプログラムをコンパイルし、jarなり何なりにしてEclipseの外部で動作させると、必ずMS932になる(Windowsの場合)

何が困るのか

もちろん、テキストファイルの読み書きでは、すべて明示的にエンコーディングを指定しているので構わないのだが、問題は外部プロセスを呼び出して、その出力を受け取ろうとする場合。

結果のjar配布物では、もちろんこれまで通りに動作するが、Eclipse上でこれをテストしようとする場合、以下のプログラムで文字化けが発生してしまう。

// 実際には読み込みにスレッドを使用していることに注意
Process process = ...
InputStream in = process.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
while (true) {
  String line = reader.readLine();
  if (line == null) break;
  output(line);
}

InpuStreamReaderにはエンコーディングを指定していないので、プラットフォームデフォルトのエンコーディングが使用されるが、Eclipseが勝手にfile.encodingを指定してしまうのだ。Windowsの場合、ここはMS932でなければならないので、Eclipseが勝手にUTF-8にすると、文字化けしてしまう。

もちろん、ここで明示的にnew InputStreamReader(in, “MS932”)とすることもできるが、そうはしたくない。Windows以外のプラットフォームでも動作させるからである。

解決策

Run configurationのVM引数に明示的に-Dfile.encoding=MS932を指定する。

問題の根源

この問題の根源は二つあると思われる。

Eclipseが余計なお世話をしている

Text file encodingの指定は、取り扱うソースファイルのエンコーディングの指定だが、なぜか読み書き対象のテキストファイルにも適用しようとし、file.encodingを指定してしまう。ここが第一の間違い。なぜこんなことをしているのか探してみたのだが、答えは得られなかった。

JavaにOSのデフォルトエンコーディングを知る方法が無い

仮にEclipseがfile.encodingを勝手に設定したとしても、その値にかかわらずOSのデフォルトエンコーディングを知る方法があれば、その値をInputSteamReaderに指定すればよいこと。しかし、これが見つからない。いったんfile.encodingが変えられてしまうと、もはやOSのエンコーディングがわからなくなる。

テキストファイルの読み書きでは自動判別なり、エンコーディング指定しての書き込みなりで対処できるが、プロセスの出力では何ともならない。例えば、Linuxでは、Shift_JISもあるだろうし、UTF-8もある。

そうであれば、本来file.encodingの設定は絶対に行ってはならないはずなのだが。。。