2011-09-15 8 views
4

私はString.format Java APIのメソッドを使って何かを記録しています。私の方法は次のようである:問題があるしかしJavaの安全String.formatとエスケープ%

public static void log(String message, Object... params){ 
    System.out.println(String.format(message, params)); 
} 

ユーザーがどこかで%文字を持つメッセージを送信した場合、それは例外をスローします。ここではシナリオです:

log("SELECT * FROM my WHERE name like '%six%'"); 

とJavaは%sを置き換えるために何かを探し(それは大丈夫です)と%'(おっと)。私はそれを修正したい。 paramsが存在しないため、%sが失われ、%'が例外となるためです。

1つの解決策はmessage.replace("%", "%%")ですが、私はそれが優雅な解決策であるかどうかはわかりません。

最も可能性が高い誤用(どこか String%sまたは %を使用しますが、パラメータを提供していない)のための簡単な解決策は、あなたの元のメソッドに加えにあなたの方法 にノーのparams過負荷を提供することで
+1

また、以下は、コールサイトで使用することができます。彼らはあなたに壊れた入力を与える場合、彼らは作業出力を期待することはできません。ただ例外を投げる。 –

+0

@Christoffer壊れた入力としてSQLの 'like'節を含むメッセージ文字列は表示されません。 – adarshr

+1

文字列に '%s'と'% 'の両方が含まれ、1つがOKとみなされ、もう1つがそうでないと、入力が壊れます。入力が 'String.format()'のフォーマット文字列で、 'like'節の'%s 'がパラメータ値に置き換えられないようにするには、 '%% s'と'%s' % 'が壊れています。 –

答えて

7

logは、所与%が書式指定として、またはパーセント記号として意図されているかどうかわかりません。次の例を考えてみましょう:

log("%s%s", "test"); 

はその"test%s""%stest"、またはエラーか?

したがって、問題は、呼び出しサイトで対処する必要があります:

escape()あなたはそれが %%ですべて %を置き換えます記述する必要があります機能です
log(escape("SELECT * FROM my WHERE name like '%six%'")); 

。 `%が`ない場合は `%のS`はOKだろう、なぜ私は表示されません

log("%s", "SELECT * FROM my WHERE name like '%six%'"); 
+0

あるいは、 'log()'メソッドの中から 'escape()'メソッドを呼び出して、操作をシームレスにしてください。 – adarshr

+1

@adarshr:それでは 'String.format()'の使用は何ですか? –

+0

私は最後のケースを使用しましたが、私のSQLは 'log("%s "、query);'のようにログに記録されます。ありがとう。 –

1

public static void log(String message) { 
    System.out.println(message); 
} 

別の方法としては、動的なしのparamsケースを検出しようとすることができ、それは少しより多くの仕事です:

public static void log(String message, Object... params) { 
    final String output; 
    if (params == null || params.length = 0) { 
    output = message; 
    } else { 
    output = String.format(message, params); 
    } 
    System.out.println(output); 
} 
+0

クライアントがformatting-capabilitiesを利用していて、 '%n'のようなことをした場合、動作しません。 – aioobe

+0

上記の2つの方法はあいまいです。なぜなら、最初の(var argsを使用すると)引数の長さが0の長さのリストを使うからです。 –

+0

@aioobe:実際には、文書化する必要がありますが、ここでは '\ n'の代わりに'%n'を使用する理由はありません。 –

0

一つの選択肢のw paramsの長さが0の場合は、文字列をprintlnに直接渡してください。 もう1つのオプションは、2つのオーバーロードを持つことです。

public static void log(String message); 
public static void log(String format, String param, String...params); 
+1

固定 'param'が必要ではないと思います。また、フォーマットパラメータは 'Object'にすることができるので、' log'は 'Object'も受け入れるべきです。 –

+0

しかし、引数なしの場合にオーバーロードが呼び出される可能性のある混乱がないので、読みやすさが向上すると思いますか? –

+2

これは本当ですが、より明白ですが、欠点があります。例えば何らかの理由で配列をすでに持っていれば(おそらく呼び出すメソッド自体は可変アリティメソッドなので)、配列をコピーして 'log'メソッドを呼び出さなければなりません。 –

関連する問題