False Positive in S3457 "String contains no format specifiers" (long)

SonarQube 8.5 (build 37579) scanning Java code with the built-in SonarWay quality profile.

Sometimes S3457 gives a false positive and claims that a log message contains no format specifiers. Example:

package com.utils;

import java.util.logging.Level;
import java.util.logging.Logger;
import com.process.customer.MalformedDataException;
import com.process.customer.PartyNotFoundException;

public class LogExample {

    private static final Logger log = Logger.getLogger(LogExample.class.getName());
    private Integer owner;

    public Integer getOwner() {
        try {
            if (owner == null)
                throw new MalformedDataException(null, null);
            if (owner == -1)
                throw new PartyNotFoundException(null, null);
        } catch (MalformedDataException | PartyNotFoundException e) {
            // False positive on this log() call
            log.log(Level.SEVERE, "Exception occured in UserBean.getOwner", e);
        }
        return owner;
    }
}

The FP is not consistent. It does not happen if

  • The above exceptions are replaced with other (Java-supplied) exceptions
  • Only one of the above exceptions is used and caught
  • The above exceptions are replaced with copies in the same package that are identical code-wise

The exceptions above are subclasses of Exception, created from another project’s WSDL and supplied by a JAR file. They have similar declarations:

package com.process.customer;

import javax.xml.ws.WebFault;

/**
 * This class was generated by the JAX-WS RI.
 * JAX-WS RI 2.2.10
 * Generated source version: 2.2
 * 
 */
@WebFault(name = "MalformedDataFault", targetNamespace = "http://customer.process.aaalife.com/")
public class MalformedDataException extends Exception
{
    /**
     * Java type that goes as soapenv:Fault detail element.
     */
    private GenericFaultBean faultInfo;

    public MalformedDataException(String message, GenericFaultBean faultInfo) {
        super(message);
        this.faultInfo = faultInfo;
    }

    public MalformedDataException(String message, GenericFaultBean faultInfo, Throwable cause) {
        super(message, cause);
        this.faultInfo = faultInfo;
    }

    public GenericFaultBean getFaultInfo() {
        return faultInfo;
    }
}

GenericFaultBean is

package com.process.customer;

import java.io.Serializable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlType;

/**
 * <p>Java class for genericFaultBean complex type.
 * 
 * <p>The following schema fragment specifies the expected content contained within this class.
 * 
 * <pre>
 * &lt;complexType name="genericFaultBean">
 *   &lt;complexContent>
 *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       &lt;sequence>
 *         &lt;element name="message" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
 *       &lt;/sequence>
 *     &lt;/restriction>
 *   &lt;/complexContent>
 * &lt;/complexType>
 * </pre>
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "genericFaultBean", propOrder = {"message"})
public class GenericFaultBean implements Serializable
{
    private final static long serialVersionUID = 1L;
    protected String message;

    public String getMessage() {
        return message;
    }

    public void setMessage(String value) {
        this.message = value;
    }
}

Fred Robinson
frobinson@aaalife.com

Hello @Fred_Robinson,

Thanks for the feedback, and the in-depth description of the problem, it is really appreciated.

The FP is not consistent.

My guess is that the analyzer cannot resolve the type of the Exceptions. It’s typically due to a project’s properties misconfiguration (probably sonar.java.libraries missing). Checks the logs of the analysis if you see something strange. In addition, I invite you to have a look there, it’s not the same rule, but I believe the resolution is similar.

In addition, the analyzer is supposed to be smart enough to detect that types are missing, but somehow strangely compute a type when using union type. I created a ticket (SONARJAVA-3621) to dig further into this.

(I’ve done a lot of debugging in my time, so I appreciate getting as much information as possible as well.)

Thanks for the pointers. I checked your link.

We are using the SonarScanner for Maven; our goals in the Jenkins job are clean install sonar:sonar. I don’t see any mention of “Bytecode of dependencies” in the resulting logs.

I’ve not set sonar.java.libraries. I will look into that.

Fred Robinson

Any new on your side?

Did the references provide help?