Eclipse - 声纳 S2629 可能误报新字符串

use*_*900 4 java eclipse sonarqube sonarlint-eclipse

我正在使用最新的 Eclipse 和 Sonar 插件

回答日志记录时,有以下行:

log.debug("Request body: {}", new String(body, "UTF-8"));
Run Code Online (Sandbox Code Playgroud)

只有在调试级别时才应该创建字符串:

/**
 * Log a message at the DEBUG level according to the specified format
 * and argument.
 * <p/>
 * <p>This form avoids superfluous object creation when the logger
 * is disabled for the DEBUG level. </p>
 *
 * @param format the format string
 * @param arg    the argument
 */
public void debug(String format, Object arg);
Run Code Online (Sandbox Code Playgroud)

但声纳将其标记为squid:S2629

“前提条件”和日志参数不应该需要求值 (squid:S2629)

并给出串联的例子

logger.log(Level.DEBUG, "出现问题:" + message); // 不合规;即使日志级别太高而无法显示 DEBUG 消息,也会执行字符串连接

这是误报声纳警告还是我遗漏了什么?

这不是这个问题的重复,该问题通常询问规则概念,即连接,但不是通过创建对象进行格式化new String

还有一个答案的链接说创建new Date()不会创建内置格式的问题:

public static void main(String[] args) {
    LOGGER.info("The program started at {}", new Date());
}

}
Run Code Online (Sandbox Code Playgroud)

以这种方式记录可以避免在实际不记录任何内容时字符串连接的性能开销。

how*_*ger 8

在非调试模式下,该行

log.debug("Request body: {}", new String(body, "UTF-8"));
Run Code Online (Sandbox Code Playgroud)

代替

log.debug(MessageFormatter.format("Request body: {}", new String(body, "UTF-8")));
Run Code Online (Sandbox Code Playgroud)

避免创建通过创建的字符串MessageFormatter.format(String messagePattern, Object arg),但不会创建由创建的其他字符串new String(body, "UTF-8")

这意味着它不是误报,因为在调用日志记录方法之前首先计算参数。

只要SLF4J 不支持 lambda 表达式来延迟评估参数(请参阅ZhekaKozlov 的评论),可以使用以下实用方法作为解决方法:

private static Object lazyToString(final Supplier<String> stringSupplier) {
    return new Object() {
        @Override
        public String toString() {
            return stringSupplier.get();
        }
    };
}
Run Code Online (Sandbox Code Playgroud)

这可用于将字节数组转换为字符串的转换仅限于调试模式:

log.debug("Request body: {}", lazyToString(() -> new String(body, StandardCharsets.UTF_8)));
Run Code Online (Sandbox Code Playgroud)