Since: PMD3.2
To make sure the full stacktrace is printed out, use the logging statement with 2 arguments: a String and a Throwable.
//CatchStatement/Block/BlockStatement/Statement/StatementExpression
/PrimaryExpression[PrimaryPrefix/Name[starts-with(@Image,
concat(ancestor::ClassOrInterfaceDeclaration/ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/FieldDeclaration
[Type//ClassOrInterfaceType[@Image='Log']]
/VariableDeclarator/VariableDeclaratorId/@Image, '.'))]]
[PrimarySuffix/Arguments[@ArgumentCount='1']]
[PrimarySuffix/Arguments//Name/@Image = ancestor::CatchStatement/FormalParameter/VariableDeclaratorId/@Image]
public class Main {
private static final Log _LOG = LogFactory.getLog( Main.class );
void bar() {
try {
} catch( Exception e ) {
_LOG.error( e ); //Wrong!
} catch( OtherException oe ) {
_LOG.error( oe.getMessage(), oe ); //Correct
}
}
}
Since: PMD3.3
A logger should normally be defined private static final and have the correct class. Private final Log log; is also allowed for rare cases where loggers need to be passed around, with the restriction that the logger needs to be passed into the constructor.
//ClassOrInterfaceBodyDeclaration[FieldDeclaration//ClassOrInterfaceType[@Image='Log']
and
not(FieldDeclaration[@Final='true'][@Static='true'][@Private='true'][.//VariableDeclaratorId[@Image=$staticLoggerName]]
//ArgumentList//ClassOrInterfaceType/@Image = ancestor::ClassOrInterfaceDeclaration/@Image)
and
not(FieldDeclaration[@Final='true'][@Private='true'][.//VariableDeclaratorId[@Image='log']]
[count(.//VariableInitializer)=0]
[ancestor::ClassOrInterfaceBody//StatementExpression[.//PrimaryExpression/descendant::*[@Image='log']][count(.//AllocationExpression)=0]]
)]
public class Foo {
// right
private static final Log LOG = LogFactory.getLog(Foo.class);
// wrong
protected Log LOG = LogFactory.getLog(Testclass.class);
}
This rule has the following properties:
| Name | Default Value | Description |
|---|---|---|
| staticLoggerName | Name of the static Logger variable |