4

I'm using String.format method of Java API to log something. My method is like:

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

However the problem is, if the user sends a message that has % character somewhere in it, it throws exception. Here's a scenario:

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

and Java looks for something to replace %s (that's ok) and %' (oops). I want to fix that. Because there there are no params and %s will be lost and %' causes exception.

One solution can be message.replace("%", "%%") but I'm not sure it is an elegant solution or not.

3
  • 1
    I don't see why %s would be OK if % isn't. If they give you broken input they can't expect working output. Just throw an exception. Commented Sep 15, 2011 at 11:16
  • @Christoffer I don't see the message string containing an SQL like clause as a broken input. Commented Sep 15, 2011 at 11:18
  • 1
    If the string contains both %s and %, and one is considered OK and the other is not, then the input is broken. If the input is a format string for String.format() and you don't want the %s in the like claused to be replaced by a parameter value, anything but %%s and %% in the input is broken. Commented Sep 15, 2011 at 11:30

3 Answers 3

7

log has no idea whether a given % is meant as a format specifier or as a percent sign. Consider the following example:

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

Is that "test%s", "%stest", or an error?

Therefore, the problem will have to be addressed at the call site:

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

where escape() is a function you'll need to write that'll replace all % with %%.

Alternatively, the following can be used at the call site:

log("%s", "SELECT * FROM my WHERE name like '%six%'");
Sign up to request clarification or add additional context in comments.

2 Comments

Or perhaps, call the escape() method from within the log() method, making the operation seamless.
I used the last case and now my SQLs are logged like log("%s", query);. Thanks.
1

A simple solution for the most likely misuse (using %s or % somewhere in the String but providing no parameters) would be to provide a no-params overload to your method in addition to your original method:

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

Alternatively you can dynamically try to detect the no-params case, but that's a bit more work:

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);
}

5 Comments

Won't work if the client exploits the formatting-capabilities and does something like %n.
The two methods above are ambiguous since the first (with the var args) will take a 0-length list of params just as well.
@aioobe: true, it would need to be documented, but I see no real reason to use %n instead of \n here.
@John B: the compiler knows to use the no-params version if possible, it will not complain.
Didn't know that. Thanks. In your opinion would it be better to have a pair of overloads as I describe in my answer to reduce user ambiguity of which method is called (even if the compiler figures it out)?
0

One option would be to pass the string directly into the println if the length of params is 0. Another options would be to have two overloads.

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

3 Comments

I don't think the fixed param is necessary. Also: format parameters can be Object, so log should accept Object as well.
But do you feel it provides more readability since there is no potential confusion over which overload is called in the no-arg case?
that's true, it's more obvious, but it has drawbacks. For example if for some reason I already have the array (possibly because the calling method is itself a variable arity method): then you'll have to copy the array to call the log method.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.