1746 lines
107 KiB
XML
1746 lines
107 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<ruleset name="jpinpoint-rules" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd" xmlns="http://pmd.sourceforge.net/ruleset/2.0.0" xmlns:fn="http://www.w3.org/TR/xpath-functions/">
|
|
<description>jPinpoint specific rules for performance aware Java coding, sponsored by Rabobank.(jpinpoint-rules)</description>
|
|
|
|
<!-- IMPORTANT NOTICE: The content of this file is generated. Do not edit this file directly since changes may be lost when this file is regenerated! -->
|
|
|
|
<!-- BEGIN Included file 'common.xml' -->
|
|
<rule name="AvoidCDIReferenceLeak"
|
|
language="java"
|
|
message="Explicit CDI references need to be destroyed otherwise they leak."
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
typeResolution="true"
|
|
externalInfoUrl="http://www.jpinpoint.com/doc/pmd_rules_performance.html#AvoidCDIReferenceLeak">
|
|
<description>Problem: A proxy object is created by CDI for explicit references, they are not de-referenced implicitly and become a memory leak.
|
|
Solution: Destroy the reference explicitly.
|
|
(jpinpoint-rules)</description>
|
|
<priority>2</priority>
|
|
<properties>
|
|
<property name="version" value="1.0"/>
|
|
<property name="xpath">
|
|
<value><![CDATA[
|
|
//Expression/PrimaryExpression/PrimaryPrefix/Name[@Image='CDI.current']/../../
|
|
PrimarySuffix[@Image = 'select'
|
|
and not
|
|
(ancestor::MethodDeclaration//TryStatement/FinallyStatement//PrimaryExpression[
|
|
PrimaryPrefix/Name/@Image='CDI.current'][PrimarySuffix/@Image = 'destroy']
|
|
[PrimarySuffix/Arguments/ArgumentList/Expression/PrimaryExpression/PrimaryPrefix/Name/@Image =
|
|
ancestor::MethodDeclaration//Expression/PrimaryExpression/PrimaryPrefix/Name[@Image='CDI.current']/../../
|
|
PrimarySuffix[@Image = 'select']/ancestor::StatementExpression/PrimaryExpression/PrimaryPrefix/Name/@Image
|
|
])
|
|
and not
|
|
(ancestor::MethodDeclaration//TryStatement/FinallyStatement//PrimaryExpression[
|
|
PrimaryPrefix/Name/@Image='CDI.current'][PrimarySuffix/@Image = 'destroy']
|
|
[PrimarySuffix/Arguments/ArgumentList/Expression/PrimaryExpression/PrimaryPrefix/Name/@Image =
|
|
ancestor::MethodDeclaration//VariableInitializer/Expression/PrimaryExpression/PrimaryPrefix/Name[@Image='CDI.current']/../../
|
|
PrimarySuffix[@Image = 'select']/ancestor::VariableDeclarator/VariableDeclaratorId/@Image
|
|
])]
|
|
]]></value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
public class CDIStuff {
|
|
|
|
private void bad() {
|
|
MyClass o = CDI.current().select(MyClass.class).get();
|
|
o.doStuff();
|
|
// bad - missing destroy in finally
|
|
}
|
|
|
|
private void good() {
|
|
MyClass o = CDI.current().select(MyClass.class).get();
|
|
try {
|
|
o.doStuff();
|
|
} finally {
|
|
CDI.current().destroy(o); // good - destroy properly
|
|
}
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="AvoidConstantsInInterface" class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java" message="Interface defines constants. It may expose implementation details." typeResolution="true"
|
|
externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Performance#JavaCodePerformance-VOEDOS04">
|
|
<description>Interface defines constants. Problem: Possibly exposes implementation details.
|
|
Solution: Make it a Class which cannot be instantiated, or an Enum. Use static imports.
|
|
(jpinpoint-rules)</description>
|
|
<priority>3</priority>
|
|
<properties>
|
|
<property name="version" value="1.0"/>
|
|
<property name="xpath">
|
|
<value><![CDATA[
|
|
//ClassOrInterfaceDeclaration[@Interface='true']
|
|
[
|
|
count(.//FieldDeclaration)>0
|
|
]
|
|
]]></value>
|
|
</property>
|
|
</properties>
|
|
</rule>
|
|
|
|
<rule name="AvoidDecimalAndChoiceFormatAsField" class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false"
|
|
dfa="false" language="java"
|
|
message="Avoid using DecimalFormat or ChoiceFormat as field since it is thread-unsafe."
|
|
typeResolution="true"
|
|
externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Performance#JavaCodePerformance-IDTF01">
|
|
<description>Problem: java.text.DecimalFormat and java.text.ChoiceFormat are thread-unsafe. The usual solution
|
|
is to create a new local one when needed in a method.
|
|
(jpinpoint-rules)</description>
|
|
<priority>2</priority>
|
|
<properties>
|
|
<property name="version" value="1.0"/>
|
|
<property name="xpath">
|
|
<value><![CDATA[
|
|
//FieldDeclaration/VariableDeclarator/VariableInitializer/Expression[typeIs('java.text.DecimalFormat') or typeIs('java.text.ChoiceFormat')]
|
|
]]></value>
|
|
</property>
|
|
</properties>
|
|
</rule>
|
|
|
|
<rule name="AvoidDeprecatedHttpConnectors" class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java" message="Avoid the use of deprecated/thread-unsafe HTTP connectors" typeResolution="true"
|
|
externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Performance#JavaCodePerformance-IBI06" >
|
|
<description>Problem: Several HTTP client connection managers are thread-unsafe which may cause session data mix-up or have other issues for which they were made deprecated.
|
|
Solutions: Use org.apache.http.impl.conn.PoolingHttpClientConnectionManager and org.apache.http.impl.client.HttpClientBuilder. (jpinpoint-rules)</description>
|
|
<priority>3</priority>
|
|
<properties>
|
|
<property name="version" value="1.0"/>
|
|
<property name="xpath">
|
|
<value><![CDATA[
|
|
//ImportDeclaration/Name[@Image='org.apache.commons.httpclient.SimpleHttpConnectionManager'
|
|
or @Image='org.apache.http.conn.ClientConnectionManager'
|
|
or @Image='org.apache.http.impl.conn.PoolingClientConnectionManager'
|
|
or @Image='org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager'
|
|
or @Image='org.apache.http.impl.conn.SingleClientConnManager'
|
|
or @Image='org.apache.http.impl.client.DefaultHttpClient'
|
|
or @Image='org.apache.http.impl.client.SystemDefaultHttpClient'
|
|
or @Image='org.apache.http.conn.ClientConnectionManager'
|
|
]
|
|
|
|
|
//TypeDeclaration//ClassOrInterfaceDeclaration//ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/FieldDeclaration/
|
|
Type/ReferenceType/ClassOrInterfaceType[typeIs('org.apache.commons.httpclient.SimpleHttpConnectionManager')
|
|
or typeIs('org.apache.http.conn.ClientConnectionManager')
|
|
or typeIs('org.apache.http.impl.conn.PoolingClientConnectionManager')
|
|
or typeIs('org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager')
|
|
or typeIs('org.apache.http.impl.conn.SingleClientConnManager')
|
|
or typeIs('org.apache.http.impl.client.DefaultHttpClient')
|
|
or typeIs('org.apache.http.impl.client.SystemDefaultHttpClient')
|
|
or typeIs('org.apache.http.conn.ClientConnectionManager')
|
|
]
|
|
|
|
|
//TypeDeclaration//ClassOrInterfaceDeclaration//ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/FieldDeclaration/
|
|
VariableDeclarator/VariableInitializer/Expression//AllocationExpression/ClassOrInterfaceType[
|
|
typeIs('org.apache.http.conn.ClientConnectionManager')
|
|
or typeIs('org.apache.http.impl.conn.PoolingClientConnectionManager')
|
|
or typeIs('org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager')
|
|
or typeIs('org.apache.http.impl.conn.SingleClientConnManager')
|
|
or typeIs('org.apache.http.impl.client.DefaultHttpClient')
|
|
or typeIs('org.apache.http.impl.client.SystemDefaultHttpClient')
|
|
or typeIs('org.apache.http.conn.ClientConnectionManager')
|
|
]
|
|
|
|
|
//AllocationExpression/ClassOrInterfaceType[typeIs('org.apache.commons.httpclient.SimpleHttpConnectionManager')]
|
|
]]></value>
|
|
</property>
|
|
</properties>
|
|
</rule>
|
|
|
|
<rule name="AvoidDuplicateAssignmentsInCases"
|
|
message="Avoid duplicate assignments in different switch cases"
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java"
|
|
typeResolution="true" externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Quality#JavaCodeQuality-CSC01">
|
|
<description>
|
|
Problem: Potential bug: expected are different assignments in different cases.
|
|
Solution: assign different values in different cases, common assignments should be taken out of the switch.
|
|
(jpinpoint-rules)</description>
|
|
<properties>
|
|
<property name="version" value="1.0"/>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//SwitchStatement/BlockStatement[
|
|
(.//AssignmentOperator/../../..//StatementExpression/Expression/PrimaryExpression/PrimaryPrefix/Name/@Image
|
|
=preceding-sibling::SwitchLabel/preceding-sibling::BlockStatement//AssignmentOperator/../../..//StatementExpression/Expression/PrimaryExpression/PrimaryPrefix/Name/@Image
|
|
or
|
|
.//AssignmentOperator/../../..//StatementExpression/Expression/PrimaryExpression/PrimaryPrefix//Literal/@Image
|
|
=preceding-sibling::SwitchLabel/preceding-sibling::BlockStatement//AssignmentOperator/../../..//StatementExpression/Expression/PrimaryExpression/PrimaryPrefix//Literal/@Image)
|
|
and
|
|
.//AssignmentOperator/../../..//StatementExpression/PrimaryExpression/PrimaryPrefix/Name/@Image
|
|
=preceding-sibling::SwitchLabel/preceding-sibling::BlockStatement//AssignmentOperator/../../..//StatementExpression/PrimaryExpression/PrimaryPrefix/Name/@Image
|
|
and
|
|
not(.//AssignmentOperator/../../..//StatementExpression/Expression/PrimaryExpression/PrimarySuffix/Arguments/@ArgumentCount > 0
|
|
or preceding-sibling::SwitchLabel[@Default='true'])
|
|
]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<priority>2</priority>
|
|
</rule>
|
|
|
|
<rule name="AvoidImplicitlyRecompilingRegex" class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java" message="String regex method, Pattern.matches or FileSystem.getPathMatcher is used.
|
|
Implicitely compiles a regex pattern, can be expensive." typeResolution="true"
|
|
externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Performance#JavaCodePerformance-IREU01">
|
|
<description>A regular expression is compiled implicitely on every invocation. Problem: this can be expensive, depending on the length of the regular expression.
|
|
Solution: Compile the regex pattern only once and assign it to a private static final Pattern field. java.util.Pattern objects are thread-safe so they can be shared among threads.
|
|
(jpinpoint-rules)</description>
|
|
<priority>2</priority>
|
|
<properties>
|
|
<property name="version" value="2.0"/>
|
|
<property name="xpath">
|
|
<value><![CDATA[
|
|
(//MethodDeclaration//PrimaryPrefix/Name[ends-with(@Image, '.replaceAll') or ends-with(@Image, '.replaceFirst') or ends-with(@Image, 'Pattern.matches')]/../../PrimarySuffix/Arguments[@ArgumentCount=2]//Expression[1]//PrimaryPrefix[
|
|
Literal[string-length(@Image) > 5 and
|
|
(matches(@Image, '[\.\$\|\(\)\[\]\{\}\^\?\*\+\\]+'))] or Name
|
|
and not(../PrimarySuffix)
|
|
and not (
|
|
Name/@Image=ancestor::MethodDeclaration//VariableDeclaratorId/@Image)
|
|
and not (
|
|
Name[@Image=ancestor::ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/FieldDeclaration/VariableDeclarator[
|
|
VariableInitializer/Expression/PrimaryExpression/PrimaryPrefix/Literal[string-length(@Image) < 6 or not
|
|
(matches(@Image, '[\.\$\|\(\)\[\]\{\}\^\?\*\+\\]+'))]
|
|
]/VariableDeclaratorId/@Image])
|
|
]
|
|
,
|
|
//MethodDeclaration//PrimaryPrefix/Name[ends-with(@Image, '.split') or ends-with(@Image, 'getPathMatcher')]/../../PrimarySuffix/Arguments[@ArgumentCount=1]//Expression[1]//PrimaryPrefix[
|
|
Literal[string-length(@Image) > 5 and
|
|
matches(@Image, '[\.\$\|\(\)\[\]\{\}\^\?\*\+\\]+')] or Name
|
|
and not(../PrimarySuffix)
|
|
and not (
|
|
Name/@Image=ancestor::MethodDeclaration//VariableDeclaratorId/@Image)
|
|
and not (
|
|
Name[@Image=ancestor::ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/FieldDeclaration/VariableDeclarator[
|
|
VariableInitializer/Expression/PrimaryExpression/PrimaryPrefix/Literal[string-length(@Image) < 6 or not
|
|
(matches(@Image, '[\.\$\|\(\)\[\]\{\}\^\?\*\+\\]+'))]
|
|
]/VariableDeclaratorId/@Image])
|
|
]
|
|
,
|
|
//MethodDeclaration//PrimarySuffix[@Image='getPathMatcher']/../PrimarySuffix/Arguments[@ArgumentCount=1]/ArgumentList/Expression[1]/PrimaryExpression/PrimaryPrefix[
|
|
Literal[string-length(@Image) > 5] or Name
|
|
and not(../PrimarySuffix)
|
|
and not (
|
|
Name/@Image=ancestor::MethodDeclaration//VariableDeclaratorId/@Image)
|
|
and not (
|
|
Name[@Image=ancestor::ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/FieldDeclaration/VariableDeclarator[
|
|
VariableInitializer/Expression/PrimaryExpression/PrimaryPrefix/Literal[string-length(@Image) < 6]]/VariableDeclaratorId/@Image])
|
|
]
|
|
,
|
|
(: --- String.matches called on formalparams, locals and fields --- :)
|
|
//MethodDeclaration//PrimaryPrefix/Name[ends-with(@Image, '.matches')]
|
|
[
|
|
(exists(index-of((ancestor::MethodDeclaration//FormalParameter[pmd-java:typeIs('java.lang.String')]/VariableDeclaratorId/@Image), substring-before(@Image,'.')))
|
|
or
|
|
exists(index-of((ancestor::MethodDeclaration//LocalVariableDeclaration/Type[pmd-java:typeIs('java.lang.String')]/../VariableDeclarator/VariableDeclaratorId/@Image), substring-before(@Image,'.')))
|
|
or
|
|
exists(index-of((ancestor::ClassOrInterfaceBody//FieldDeclaration[pmd-java:typeIs('java.lang.String')]/VariableDeclarator/VariableDeclaratorId/@Image), substring-before(@Image,'.'))))
|
|
and
|
|
(: for matches param is >5 literal or something named :)
|
|
../../PrimarySuffix/Arguments[@ArgumentCount=1]//Expression[1]//PrimaryPrefix[
|
|
Literal[string-length(@Image) > 5] or Name
|
|
(: exclude method calls :)
|
|
and not(../PrimarySuffix)
|
|
(: exclude for param is method arg or local :)
|
|
and not (
|
|
Name/@Image=ancestor::MethodDeclaration//VariableDeclaratorId/@Image)
|
|
(: exclude for param is short fields :)
|
|
and not (
|
|
Name[@Image=ancestor::ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/FieldDeclaration/VariableDeclarator[
|
|
VariableInitializer/Expression/PrimaryExpression/PrimaryPrefix/Literal[string-length(@Image) < 6]
|
|
]/VariableDeclaratorId/@Image])
|
|
]])
|
|
]]></value>
|
|
</property>
|
|
</properties>
|
|
</rule>
|
|
|
|
<rule name="AvoidInMemoryStreamingDefaultConstructor" class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java" message="Default capacity constructor of ByteArrayOutputStream or StringWriter is used, it usually needs expensive expansions." typeResolution="true"
|
|
externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Performance#JavaCodePerformance-ISIO01">
|
|
<description>Default constructor of ByteArrayOutputStream or StringWriter is used. Problem: It allocates a small buffer as capacity which usually needs several expensive expansions.
|
|
Solution: Presize the ByteArrayOutputStream or StringWriter with an initial capacity such that an expansion is not needed in most cases.
|
|
(jpinpoint-rules)</description>
|
|
<priority>2</priority>
|
|
<properties>
|
|
<property name="version" value="1.0"/>
|
|
<property name="xpath">
|
|
<value><![CDATA[
|
|
//TypeDeclaration/ClassOrInterfaceDeclaration/ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration
|
|
//PrimaryExpression/PrimaryPrefix/AllocationExpression/ClassOrInterfaceType[typeIs('java.io.ByteArrayOutputStream') or typeIs('java.io.StringWriter')]
|
|
[not(../Arguments/ArgumentList)]
|
|
]]></value>
|
|
</property>
|
|
</properties>
|
|
</rule>
|
|
|
|
<rule name="AvoidMultipleConcatStatements" class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java" message="Multiple statements concatenate to the same String. Use StringBuilder append." typeResolution="true"
|
|
externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Performance#JavaCodePerformance-ISU02">
|
|
<description>Multiple statements concatenate to the same String. Problem: Each statement with one or more +-operators creates a hidden temporary StringBuilder, a char[] and a new String object, which all have to be garbage collected.
|
|
Solution: Use StringBulder.append.
|
|
(jpinpoint-rules)</description>
|
|
<priority>2</priority>
|
|
<properties>
|
|
<property name="version" value="1.0"/>
|
|
<property name="xpath">
|
|
<value><![CDATA[
|
|
//MethodDeclaration/Block[
|
|
count(
|
|
./BlockStatement/Statement//StatementExpression/PrimaryExpression/PrimaryPrefix/Name
|
|
[@Image=./../../../../../../../../../../../..//VariableDeclaratorId/attribute::Image
|
|
and
|
|
./../../../../../../..//VariableDeclaratorId/../../Type/ReferenceType/ClassOrInterfaceType[typeIs('java.lang.String')]
|
|
]
|
|
/../../../AssignmentOperator[@Image='+=']/
|
|
../Expression//PrimaryExpression/PrimaryPrefix/Name) > 1]/BlockStatement[position()=last()]
|
|
|
|
|
//MethodDeclaration/Block[
|
|
count(
|
|
./BlockStatement/Statement//StatementExpression[
|
|
./PrimaryExpression/PrimaryPrefix/Name[
|
|
@Image = ../../../Expression/AdditiveExpression/PrimaryExpression/PrimaryPrefix/Name/@Image
|
|
and
|
|
@Image = ./../../../../../../../..//VariableDeclaratorId/../../Type/ReferenceType/ClassOrInterfaceType[typeIs('java.lang.String')]/../../../VariableDeclarator/VariableDeclaratorId/attribute::Image
|
|
]
|
|
]) > 1 ]//BlockStatement[position()=last()]//StatementExpression/Expression/AdditiveExpression[@Image = '+']
|
|
]]></value>
|
|
</property>
|
|
</properties>
|
|
</rule>
|
|
|
|
<rule name="AvoidRecompilingPatterns" class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java" message="Pattern.compile is used in a method. Compiling a regex pattern can be expensive, make it a static final field." typeResolution="true"
|
|
externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Performance#JavaCodePerformance-IREU02">
|
|
<description>A regular expression is compiled on every invocation. Problem: this can be expensive, depending on the length of the regular expression.
|
|
Solution: Usually a pattern is a literal, not dynamic and can be compiled only once. Assign it to a private static field. java.util.Pattern objects are thread-safe so they can be shared among threads.
|
|
(jpinpoint-rules)</description>
|
|
<priority>2</priority>
|
|
<properties>
|
|
<property name="version" value="1.0"/>
|
|
<property name="xpath">
|
|
<value><![CDATA[
|
|
//TypeDeclaration/ClassOrInterfaceDeclaration/ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/MethodDeclaration
|
|
//PrimaryExpression/PrimaryPrefix/Name[ends-with(@Image, '.compile') and
|
|
count(../../PrimarySuffix/Arguments/ArgumentList/Expression//PrimaryExpression) = 1
|
|
and not (
|
|
../../PrimarySuffix/Arguments/ArgumentList/Expression/PrimaryExpression/PrimaryPrefix/Name/@Image=
|
|
ancestor::MethodDeclaration/MethodDeclarator/FormalParameters/FormalParameter/VariableDeclaratorId/@Image)]
|
|
]]></value>
|
|
</property>
|
|
</properties>
|
|
</rule>
|
|
|
|
<rule name="AvoidRecompilingXPathExpression" class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java" message="XPathExpression is created and compiled every time. Beware it is thread-unsafe." typeResolution="true"
|
|
externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Performance#JavaCodePerformance-UX02">
|
|
<description>XPathExpression is created and compiled on every method call. Problem: Creation XPath and compilation of XPathExpression takes time. It may slow down your application.
|
|
Solution: 1. Avoid XPath usage. 2. Since XPath and XPathExpression classes are thread-unsafe, they are not easily cached. Caching in Thread locals may be a solution.
|
|
(jpinpoint-rules)</description>
|
|
<priority>2</priority>
|
|
<properties>
|
|
<property name="version" value="1.0"/>
|
|
<property name="xpath">
|
|
<value><![CDATA[
|
|
//TypeDeclaration/ClassOrInterfaceDeclaration/ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/MethodDeclaration
|
|
//PrimaryExpression/PrimaryPrefix/Name[ends-with(@Image,'.newXPath')]
|
|
/ancestor::ClassOrInterfaceBodyDeclaration
|
|
//PrimaryExpression/PrimaryPrefix/Name[ends-with(@Image, '.compile')]
|
|
]]></value>
|
|
</property>
|
|
</properties>
|
|
</rule>
|
|
|
|
<rule name="AvoidRecreatingDateTimeFormatter"
|
|
message="Avoid recreating DateTimeFormatter, it is relatively expensive."
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java"
|
|
typeResolution="true" externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Performance#JavaCodePerformance-IDTF02">
|
|
<description>
|
|
Problem: Recreating a DateTimeFormatter is relatively expensive.
|
|
Solution: org.joda.time.format.DateTimeFormatter or Java 8 java.time.DateTimeFormatter is thread-safe and can be shared among threads. Create the
|
|
formatter from a pattern only once, to initialize a static final field.
|
|
(jpinpoint-rules)</description>
|
|
<properties>
|
|
<property name="version" value="1.0"/>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//FieldDeclaration[@Final='false' or @Static='false']//ReferenceType/ClassOrInterfaceType[typeIs('org.joda.time.format.DateTimeFormatter') or typeIs('org.threeten.bp.format.DateTimeFormatter') or typeIs('java.time.format.DateTimeFormatter')] |
|
|
//MethodDeclaration/Block//ReferenceType/ClassOrInterfaceType[typeIs('org.joda.time.format.DateTimeFormatter') or typeIs('org.threeten.bp.format.DateTimeFormatter') or typeIs('java.time.format.DateTimeFormatter')]
|
|
[ancestor::LocalVariableDeclaration/VariableDeclarator/VariableInitializer/Expression//PrimaryPrefix/Literal] |
|
|
//MethodDeclaration/Block/BlockStatement//Expression//AllocationExpression/ClassOrInterfaceType[typeIs('org.joda.time.format.DateTimeFormatter') or typeIs('org.threeten.bp.format.DateTimeFormatter') or typeIs('java.time.format.DateTimeFormatter')] |
|
|
//MethodDeclaration/Block/BlockStatement//Expression/PrimaryExpression/PrimaryPrefix/Name[starts-with(@Image, 'ISODateTimeFormat.')] |
|
|
//MethodDeclaration/Block/BlockStatement//Expression/PrimaryExpression/PrimaryPrefix/Name[starts-with(@Image, 'DateTimeFormat.')
|
|
and not (ends-with(@Image, 'forPattern'))] |
|
|
//MethodDeclaration/Block/BlockStatement//Expression/PrimaryExpression/PrimaryPrefix/Name[starts-with(@Image, 'DateTimeFormat.forPattern')]
|
|
[ancestor::Expression//PrimaryPrefix/Literal] |
|
|
//MethodDeclaration/Block/BlockStatement//Expression/PrimaryExpression/PrimarySuffix[@Image='toFormatter']
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<priority>2</priority>
|
|
</rule>
|
|
|
|
<rule name="AvoidReflectionInToStringAndHashCode" class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java" message="Reflection is used in toString or hashCode, which is expensive." typeResolution="true"
|
|
externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Performance#JavaCodePerformance-UUOR01">
|
|
<description>Problem: Reflection is relatively expensive.
|
|
Solution: Avoid to use reflection. Use the non-reflective, explicit way, preferably using Guava.
|
|
(jpinpoint-rules)</description>
|
|
<priority>2</priority>
|
|
<properties>
|
|
<property name="version" value="1.0"/>
|
|
<property name="xpath">
|
|
<value><![CDATA[
|
|
//PrimaryPrefix/AllocationExpression/ClassOrInterfaceType
|
|
[
|
|
typeIs('org.apache.commons.lang.builder.EqualsBuilder')
|
|
or typeIs('org.apache.commons.lang.builder.HashCodeBuilder')
|
|
]
|
|
[../../../PrimarySuffix[1]
|
|
[
|
|
@Image='reflectionEquals'
|
|
or @Image='reflectionHashCode'
|
|
]
|
|
] |
|
|
//PrimaryPrefix/Name
|
|
[
|
|
@Image='EqualsBuilder.reflectionEquals'
|
|
or @Image='HashCodeBuilder.reflectionHashCode'
|
|
]
|
|
]]></value>
|
|
</property>
|
|
</properties>
|
|
</rule>
|
|
|
|
<rule name="AvoidSimpleDateFormat" class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java" message="SimpleDateFormat is used. Since it is thread-unsafe, it needs expensive recreation." typeResolution="true"
|
|
externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Performance#JavaCodePerformance-IDTF01">
|
|
<description>Problem: java.util.SimpleDateFormat is thread-unsafe. The usual solution is to create a new one when needed in a method. Creating SimpleDateFormat is relatively expensive.
|
|
Solution: Use a Joda-Time DateTimeFormat to create a specific DateTimeFormatter or Java 8 java.time.DateTimeFormatter. These classes are immutable, thus thread-safe and can be made static.
|
|
(jpinpoint-rules)</description>
|
|
<priority>2</priority>
|
|
<properties>
|
|
<property name="version" value="1.0"/>
|
|
<property name="xpath">
|
|
<value><![CDATA[
|
|
//AllocationExpression/ClassOrInterfaceType[typeIs('java.text.SimpleDateFormat')]
|
|
]]></value>
|
|
</property>
|
|
</properties>
|
|
</rule>
|
|
|
|
<rule name="AvoidStringBuffer" class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java" message="StringBuffer is used. It introduces locking overhead, use StringBuilder." typeResolution="true"
|
|
externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Performance#JavaCodePerformance-ISU01" >
|
|
<description>Problem: StringBuffer introduces locking overhead because it is thread safe. Its thread-safety is rarely needed.
|
|
Solution: Replace StringBuffer by StringBuilder. (jpinpoint-rules)</description>
|
|
<priority>3</priority>
|
|
<properties>
|
|
<property name="version" value="1.0"/>
|
|
<property name="xpath">
|
|
<value><![CDATA[
|
|
//VariableDeclarator[../Type/ReferenceType/ClassOrInterfaceType[typeIs('java.lang.StringBuffer')]]
|
|
]]></value>
|
|
</property>
|
|
</properties>
|
|
</rule>
|
|
|
|
<rule name="AvoidUnconditionalBuiltLogStrings" class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java" message="Log String is built irrespective of log level." typeResolution="true"
|
|
externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Performance#JavaCodePerformance-IL02">
|
|
<description>A String to be logged is built unconditionally. Problem: String building, concatenation and/or other operations happen before the debug, trace or info method executes, so independent of the need to actually log. Concatenation is relatively expensive.
|
|
Solution: Build the String conditionally on the log level, within an if statement.
|
|
(jpinpoint-rules)</description>
|
|
<priority>2</priority>
|
|
<properties>
|
|
<property name="version" value="1.0"/>
|
|
<property name="xpath">
|
|
<value><![CDATA[
|
|
//MethodDeclaration/Block/BlockStatement/Statement//StatementExpression/PrimaryExpression/PrimaryPrefix/Name[
|
|
(substring-before(@Image, '.') =
|
|
ancestor::MethodDeclaration//BlockStatement/Statement/StatementExpression/PrimaryExpression/PrimaryPrefix/Name[ends-with
|
|
(@Image, '.debug') or ends-with(@Image, '.trace') or ends-with(@Image, '.info')]
|
|
/../../PrimarySuffix/Arguments/ArgumentList/Expression/PrimaryExpression/PrimaryPrefix/Name/attribute::Image
|
|
and
|
|
substring-after(@Image, '.') = 'append')
|
|
and count(ancestor::IfStatement) = 0
|
|
and
|
|
count(ancestor::MethodDeclaration/Block/BlockStatement/Statement//PrimaryExpression/PrimaryPrefix/Name[
|
|
(substring-before(@Image, '.') =
|
|
ancestor::MethodDeclaration//BlockStatement/Statement//PrimaryExpression/PrimaryPrefix/Name[ends-with
|
|
(@Image, '.debug') or ends-with(@Image, '.trace') or ends-with(@Image, '.info')]
|
|
/../../PrimarySuffix/Arguments/ArgumentList//PrimaryExpression/PrimaryPrefix/Name/attribute::Image
|
|
and
|
|
substring-after(@Image, '.') != 'append')]) = 0
|
|
]
|
|
]]></value>
|
|
</property>
|
|
</properties>
|
|
</rule>
|
|
|
|
<rule name="AvoidWideScopeXPathExpression" class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java" message="XPathExpression targets a wide scope, this is potentially slow." typeResolution="true"
|
|
externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Performance#JavaCodePerformance-UX01">
|
|
<description>The XPathExpression targets a wide scope since it starts with '//'. Problem: XPath has to search in a wide scope for occurrences, this may take a while.
|
|
Solution: 1. Avoid XPath usage. 2. Make the scope as narrow as possible, do not start with '//'.
|
|
(jpinpoint-rules)</description>
|
|
<priority>2</priority>
|
|
<properties>
|
|
<property name="version" value="1.0"/>
|
|
<property name="xpath">
|
|
<value><![CDATA[
|
|
//TypeDeclaration/ClassOrInterfaceDeclaration/ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/MethodDeclaration
|
|
//PrimaryExpression/PrimarySuffix[
|
|
Arguments/ArgumentList/Expression/PrimaryExpression/PrimaryPrefix/
|
|
Literal[starts-with(@Image, '"//')]
|
|
and
|
|
../PrimaryPrefix/Name[ends-with(@Image, '.compile')]
|
|
]
|
|
]]></value>
|
|
</property>
|
|
</properties>
|
|
</rule>
|
|
|
|
<rule name="AvoidXMLGregorianCalendar" class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java" message="XMLGregorianCalendar is used. It is slow in JAXB." typeResolution="true"
|
|
externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Performance#JavaCodePerformance-IUOXAR05">
|
|
<description>Problem: XMLGregorianCalendar is a large object, involving substantial processing. It is created with the poorly performing DatatypeFactory.
|
|
Solution: Add a converter for alternative date handling with joda-time or Java 8 java.time.
|
|
(jpinpoint-rules)</description>
|
|
<priority>2</priority>
|
|
<properties>
|
|
|
|
<property name="version" value="1.0"/>
|
|
<property name="xpath">
|
|
<value><![CDATA[
|
|
//TypeDeclaration/ClassOrInterfaceDeclaration/ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/
|
|
FieldDeclaration/Type/ReferenceType/ClassOrInterfaceType[typeIs('javax.xml.datatype.XMLGregorianCalendar')]
|
|
|
|
|
//TypeDeclaration/ClassOrInterfaceDeclaration/ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/
|
|
MethodDeclaration//LocalVariableDeclaration/Type/ReferenceType/ClassOrInterfaceType[typeIs('javax.xml.datatype.XMLGregorianCalendar')]
|
|
]]></value>
|
|
</property>
|
|
</properties>
|
|
</rule>
|
|
|
|
<rule name="AvoidXPathAPIUsage" class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java" message="XPathAPI is used. XPathAPI implementation has bad performance." typeResolution="true"
|
|
externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Performance#JavaCodePerformance-UX03">
|
|
<description>XPathAPI is used. Problem: XPathAPI implementation is slow.
|
|
Solution: 1. try to avoid using XPathAPI. 2. improve performance by using jvm parameters and possibly CachedXPathAPI.
|
|
(jpinpoint-rules)</description>
|
|
<priority>2</priority>
|
|
<properties>
|
|
<property name="version" value="1.0"/>
|
|
<property name="xpath">
|
|
<value><![CDATA[
|
|
//TypeDeclaration/ClassOrInterfaceDeclaration/ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration
|
|
//PrimaryExpression/PrimaryPrefix/Name[starts-with(@Image, 'XPathAPI.')]
|
|
]]></value>
|
|
</property>
|
|
</properties>
|
|
</rule>
|
|
|
|
<rule name="AvoidXPathUsage" class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java" message="XPath is used. XPath implementation has bad performance." typeResolution="true"
|
|
externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Performance#JavaCodePerformance-UX03">
|
|
<description>XPath is used. Problem: XPath implementation is slow.
|
|
Solution: 1. avoid using XPath. 2. improve performance by using jvm parameters and possibly Cached XPath API.
|
|
(jpinpoint-rules)</description>
|
|
<priority>3</priority>
|
|
<properties>
|
|
<property name="version" value="1.0"/>
|
|
<property name="xpath">
|
|
<value><![CDATA[
|
|
//TypeDeclaration/ClassOrInterfaceDeclaration/ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration
|
|
//PrimaryExpression/PrimaryPrefix/Name[@Image='XPathFactory.newInstance']
|
|
]]></value>
|
|
</property>
|
|
</properties>
|
|
</rule>
|
|
|
|
<rule name="HttpClientBuilderWithoutDisableConnectionState" class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java" message="A HttpClient builder is used and disableConnectionState is not called. HTTP client tracks connection state while using TLS" typeResolution="true"
|
|
externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Performance#JavaCodePerformance-IBI07">
|
|
<description>Problem: NTLM authenticated connections and SSL/TLS connections with client certificate authentication are stateful: they have a specific user identity/security context per session. If HttpClients have enabled connection state tracking which is the default, established TLS connections will not be reused because it is assumed that the user identity or security context may differ.
|
|
Then performance will suffer due to a full TLS handshake for each request.
|
|
Solution: HttpClients should disable connection state tracking in order to reuse TLS connections, since service calls for one pool have the same user identity/security context for all sessions. (jpinpoint-rules)</description>
|
|
<priority>2</priority>
|
|
<properties>
|
|
<property name="version" value="2.0"/>
|
|
<property name="xpath">
|
|
<value><![CDATA[
|
|
(:locally created http client builder without disableConnectionState :)
|
|
//MethodDeclaration//PrimaryExpression/PrimaryPrefix/Name[
|
|
(@Image="HttpClientBuilder.create" or @Image="HttpAsyncClientBuilder.create" or @Image="HttpClients.custom") and not(
|
|
ancestor::MethodDeclaration//PrimarySuffix/@Image="disableConnectionState")]
|
|
,
|
|
(: method param http client builder without disableConnectionState :)
|
|
//MethodDeclaration//FormalParameter//ClassOrInterfaceType[
|
|
(@Image="HttpClientBuilder" or @Image="HttpAsyncClientBuilder" or @Image="HttpClients") and not(
|
|
ancestor::MethodDeclaration//PrimarySuffix/@Image="disableConnectionState")]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
</rule>
|
|
|
|
<rule name="ImplementEqualsHashCodeOnValueObjects"
|
|
message="Equals and/or hashCode is missing for a value object."
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java"
|
|
typeResolution="true" externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Performance#JavaCodePerformance-IncorrectequalsandhashCode">
|
|
<description>
|
|
Problem: If equals and hashCode are not defined, they don't meet the programmer's expectations and the requirements for use with the collections API. It may result in unexpected, undesired behavior.
|
|
Solution: Add proper equals and hashCode methods that meet the equals-hashCode contract to all objects which might anyhow be put in a Map, Set or other collection. If the object should never be checked for equality or used in a collection, also add those methods and let them throw UnsupportedOperationException to fail fast. @Xml... and @Entity objects are ignored because they are assumed to be not used as value objects.
|
|
(jpinpoint-rules)</description>
|
|
<properties>
|
|
<property name="version" value="1.0"/>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//TypeDeclaration[not(./Annotation//Name[@Image='Data' or @Image='Value' or @Image='EqualsAndHashCode'
|
|
or @Image='Singleton' or @Image='Component' or @Image='Service' or @Image='Repository' or @Image='Configuration' or @Image='Endpoint' or @Image='RestController' or @Image='ControllerAdvice'
|
|
or starts-with(@Image, 'Xml') or @Image='Entity' or @Image='Embeddable' or @Image='MappedSuperclass'])]
|
|
/ClassOrInterfaceDeclaration[@Interface='false' and @Abstract='false']
|
|
[not(./ExtendsList/ClassOrInterfaceType[ends-with(@Image, 'Exception') or ends-with(@Image, 'Throwable')])]
|
|
/ClassOrInterfaceBody[ClassOrInterfaceBodyDeclaration/FieldDeclaration[@Static='false']
|
|
[
|
|
(not (../Annotation//Name[@Image = 'XmlElement']))
|
|
and
|
|
(
|
|
ancestor::ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/MethodDeclaration
|
|
[@Public='true' and @Static='false']/MethodDeclarator[starts-with(@Image, 'get') and string-length(@Image) > 3 or starts-with(@Image, 'is') and string-length(@Image) > 2]
|
|
[../ResultType/Type/ReferenceType/ClassOrInterfaceType/@Image =
|
|
ancestor::ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/FieldDeclaration[@Static='false']/Type/ReferenceType/ClassOrInterfaceType/@Image]
|
|
)
|
|
and
|
|
(not (
|
|
ancestor::ClassOrInterfaceBody//MethodDeclaration[@Public='true' and @Static='false']/MethodDeclarator[@Image='equals' or @Image='hashCode'])
|
|
)
|
|
and
|
|
((ancestor::ClassOrInterfaceBody//MethodDeclaration[@Public='true' and @Static='false']/MethodDeclarator/@Image='toString'
|
|
and
|
|
count(ancestor::ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/FieldDeclaration[@Static='false']) <=
|
|
(1 + count(ancestor::ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/MethodDeclaration
|
|
[@Public='true' and @Static='false']/MethodDeclarator[starts-with(@Image, 'get') and string-length(@Image) > 3 or starts-with(@Image, 'is') and string-length(@Image) > 2]))
|
|
)
|
|
or
|
|
ancestor::ClassOrInterfaceDeclaration[ends-with(@Image, 'Dto')]
|
|
or
|
|
count(ancestor::ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/FieldDeclaration[@Static='false']) =
|
|
count(ancestor::ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/MethodDeclaration
|
|
[@Public='true' and @Static='false']/MethodDeclarator[starts-with(@Image, 'get') and string-length(@Image) > 3 or starts-with(@Image, 'is') and string-length(@Image) > 2])
|
|
)]
|
|
]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<priority>3</priority>
|
|
</rule>
|
|
|
|
<rule name="JAXBContextCreatedForEachMethodCall" class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java" message="JAXBContext is created for each method call, which is expensive." typeResolution="true"
|
|
externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Performance#JavaCodePerformance-IUOXAR04">
|
|
<description>Problem: JAXBContext creation is expensive because it does much class loading.
|
|
Solution: Since JAXBContext objects are thread safe, they can be shared between requests and reused. So, reuse created instances, e.g. as singletons.
|
|
(jpinpoint-rules)</description>
|
|
<priority>2</priority>
|
|
<properties>
|
|
<property name="version" value="1.0"/>
|
|
<property name="xpath">
|
|
<value><![CDATA[
|
|
//MethodDeclaration//Expression/PrimaryExpression/PrimaryPrefix/Name[@Image = 'JAXBContext.newInstance']
|
|
]]></value>
|
|
</property>
|
|
</properties>
|
|
</rule>
|
|
|
|
<rule name="MDCPutWithoutRemove" message="MDC put is used without finally remove." class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java" typeResolution="true" externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Performance#JavaCodePerformance-IL04">
|
|
<description>
|
|
MDC values are added for logging, but not removed. Problem: MDC values can leak to other user transactions (requests) and log incorrect information. Solution: remove the MDC value in a finally clause.
|
|
(jpinpoint-rules)</description>
|
|
<properties>
|
|
<property name="version" value="2.0"/>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//MethodDeclaration//StatementExpression//Name[@Image='MDC.put']
|
|
/../../PrimarySuffix/Arguments/ArgumentList/Expression[1]/PrimaryExpression/PrimaryPrefix/Literal[not(@Image=
|
|
ancestor::MethodDeclaration//TryStatement/FinallyStatement//StatementExpression//Name[@Image='MDC.remove']
|
|
/../../PrimarySuffix/Arguments/ArgumentList/Expression[1]/PrimaryExpression/PrimaryPrefix/Literal/@Image)
|
|
and not(ancestor::MethodDeclaration//TryStatement/FinallyStatement//StatementExpression//Name[@Image='MDC.clear'])
|
|
]
|
|
|
|
|
//MethodDeclaration//StatementExpression//Name[@Image='MDC.put']
|
|
/../../PrimarySuffix/Arguments/ArgumentList/Expression[1]/PrimaryExpression/PrimaryPrefix/Name[not(@Image=
|
|
ancestor::MethodDeclaration//TryStatement/FinallyStatement//StatementExpression//Name[@Image='MDC.remove']
|
|
/../../PrimarySuffix/Arguments/ArgumentList/Expression[1]/PrimaryExpression/PrimaryPrefix/Name/@Image)
|
|
and not(ancestor::MethodDeclaration//TryStatement/FinallyStatement//StatementExpression//Name[@Image='MDC.clear'])
|
|
]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<priority>2</priority>
|
|
</rule>
|
|
|
|
<rule name="MinimizeAttributesInSession" class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java" message="Attribute is set in the session, yet not removed. This may bloat the session." typeResolution="true"
|
|
externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Performance#JavaCodePerformance-TMSU01">
|
|
<description>An attribute is set in the session and not removed. Problem: This may be a large object and data in the sessions takes heap space and stay in the session until time-out. This may take substantial heap space.
|
|
Solution: remove the attribute if not really needed in the session, remove it from the session as soon as possible. Alternatively, use render parameters.
|
|
(jpinpoint-rules)</description>
|
|
<priority>2</priority>
|
|
<properties>
|
|
<property name="version" value="1.0"/>
|
|
<property name="xpath">
|
|
<value><![CDATA[
|
|
//ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/MethodDeclaration//Block/BlockStatement/Statement[
|
|
./StatementExpression/PrimaryExpression/PrimarySuffix[ends-with(@Image, 'setAttribute')]
|
|
/ancestor::ClassOrInterfaceBodyDeclaration//ClassOrInterfaceBody[not(
|
|
ClassOrInterfaceBodyDeclaration/MethodDeclaration//Block/BlockStatement/Statement/StatementExpression/PrimaryExpression/PrimarySuffix[ends-with(@Image, 'removeAttribute')]
|
|
or
|
|
ClassOrInterfaceBodyDeclaration/MethodDeclaration//Block/BlockStatement/Statement/StatementExpression/PrimaryExpression/PrimaryPrefix/Name[ends-with(@Image, 'removeAttribute')]
|
|
)]]
|
|
|
|
|
//ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/MethodDeclaration//Block/BlockStatement/Statement[
|
|
./StatementExpression/PrimaryExpression/PrimaryPrefix/Name[ends-with(@Image, 'setAttribute')]
|
|
/ancestor::ClassOrInterfaceBodyDeclaration//ClassOrInterfaceBody[not(
|
|
ClassOrInterfaceBodyDeclaration/MethodDeclaration//Block/BlockStatement/Statement/StatementExpression/PrimaryExpression/PrimarySuffix[ends-with(@Image, 'removeAttribute')]
|
|
or
|
|
ClassOrInterfaceBodyDeclaration/MethodDeclaration//Block/BlockStatement/Statement/StatementExpression/PrimaryExpression/PrimaryPrefix/Name[ends-with(@Image, 'removeAttribute')]
|
|
)]]
|
|
|
|
|
//ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/MethodDeclaration//Block/BlockStatement/Statement[
|
|
.//StatementExpression/PrimaryExpression/PrimaryPrefix/Name[@Image = 'PortletUtils.setSessionAttribute']
|
|
/ancestor::ClassOrInterfaceBodyDeclaration//ClassOrInterfaceBody[not(
|
|
ClassOrInterfaceBodyDeclaration/MethodDeclaration//Block/BlockStatement//Statement/StatementExpression/PrimaryExpression/PrimaryPrefix/Name[@Image = 'PortletUtils.setSessionAttribute']
|
|
/../../PrimarySuffix/Arguments/ArgumentList/Expression/PrimaryExpression/PrimaryPrefix/Literal/NullLiteral
|
|
)]]
|
|
]]></value>
|
|
</property>
|
|
</properties>
|
|
</rule>
|
|
|
|
<rule name="ObjectMapperCreatedForEachMethodCall" message="An ObjectMapper is created for each method call, which is expensive." class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java" typeResolution="true" externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Performance#JavaCodePerformance-IUOJAR01">
|
|
<description>Problem: Jackson ObjectMapper creation is expensive because it does much class loading.
|
|
Solution: Since ObjectMapper objects are thread-safe after configuration in one thread, they can be shared afterwards between requests and reused. So, reuse created instances, from a static field.
|
|
(jpinpoint-rules)</description>
|
|
<priority>2</priority>
|
|
<properties>
|
|
<property name="version" value="1.0"/>
|
|
<property name="xpath">
|
|
<value><![CDATA[
|
|
//MethodDeclaration//Expression/PrimaryExpression/PrimaryPrefix/AllocationExpression/ClassOrInterfaceType[
|
|
(typeIs('com.fasterxml.jackson.databind.ObjectMapper')) and
|
|
not(ancestor::TypeDeclaration/Annotation/MarkerAnnotation/Name/@Image='Configuration')
|
|
]
|
|
]]></value>
|
|
</property>
|
|
</properties>
|
|
</rule>
|
|
|
|
<rule name="UnconditionalConcatInLogArgument" class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java" message="String concatenation (+) is executed regardless of log level and can be expensive" typeResolution="true"
|
|
externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Performance#JavaCodePerformance-IL01">
|
|
<description>Problem: String concatenation (+) is executed regardless of log level and can be expensive.
|
|
Solution: Use SLF4J formatting with {}-placeholders or log and format conditionally. (jpinpoint-rules)</description>
|
|
<priority>2</priority>
|
|
<properties>
|
|
<property name="version" value="1.0"/>
|
|
<property name="xpath">
|
|
<value><![CDATA[
|
|
//PrimaryPrefix/Name[ends-with(@Image,'.trace') or ends-with(@Image,'.debug') or ends-with(@Image,'.info')]/../../PrimarySuffix/Arguments/ArgumentList/Expression/AdditiveExpression
|
|
[PrimaryExpression/PrimaryPrefix/Name]
|
|
[not(ancestor::IfStatement/Expression/PrimaryExpression/PrimaryPrefix/Name[
|
|
ends-with(@Image,'.isTraceEnabled')
|
|
or ends-with(@Image,'.isDebugEnabled')
|
|
or ends-with(@Image,'.isInfoEnabled')
|
|
or ends-with(@Image,'.isLoggable')
|
|
])]
|
|
]]></value>
|
|
</property>
|
|
</properties>
|
|
</rule>
|
|
|
|
<rule name="UnconditionalOperationOnLogArgument" class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java" message="Operation is executed regardless of log level and can be expensive" typeResolution="true"
|
|
externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Performance#JavaCodePerformance-IL03">
|
|
<description>Problem: An operation is executed regardless of log level. This could be much processing while the result is typically not used. Detected are obj.toString() and operations with one or more arguments except usually cheap obj.get(arg).
|
|
Solution: Execute the operation only conditionally and utilize SLF4J formatting with {}-placeholders. (jpinpoint-rules)</description>
|
|
<priority>2</priority>
|
|
<properties>
|
|
<property name="version" value="2.0"/>
|
|
<property name="xpath">
|
|
<value><![CDATA[
|
|
//PrimaryPrefix/Name
|
|
(: log levels typically/often not enabled :)
|
|
[
|
|
ends-with(@Image,'.trace')
|
|
or ends-with(@Image,'.debug')
|
|
or ends-with(@Image,'.info')
|
|
]
|
|
(: no violation if conditionally: only executed if level enabled is okay :)
|
|
[not(ancestor::IfStatement/Expression//PrimaryPrefix/Name
|
|
[
|
|
ends-with(@Image,'.isTraceEnabled')
|
|
or ends-with(@Image,'.isDebugEnabled')
|
|
or ends-with(@Image,'.isInfoEnabled')
|
|
or ends-with(@Image,'.isLoggable')
|
|
])
|
|
]
|
|
(: in the log method :)
|
|
/../../PrimarySuffix/Arguments/ArgumentList/Expression//PrimaryExpression
|
|
[
|
|
(: toString on argument :)
|
|
PrimaryPrefix/Name[ends-with(@Image,'.toString')]
|
|
or
|
|
(: a method call with an argument list :)
|
|
(PrimarySuffix/Arguments/ArgumentList)
|
|
(: exclude a simple get(i), like list.get(0) or map.get(key), assumed to be fast :)
|
|
and not (PrimaryPrefix/Name[ends-with(@Image,'.get')])
|
|
]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
LOG.debug("customer = {}", customer.toString()); // bad
|
|
LOG.debug("Complete Soap response: {}", getSoapMsgAsString(context.getMessage())); // bad
|
|
|
|
LOG.debug("customer = {}", customer); // good
|
|
if (LOG.isDebugEnabled()) { // good
|
|
LOG.debug("Complete Soap response: {}", getSoapMsgAsString(context.getMessage()));
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="UsingSuppressWarnings" class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java" message="Using SuppressWarnings." typeResolution="true"
|
|
externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Performance">
|
|
<description>(Informative) Problem: This rule detects problems, suppressing them without full knowledge can lead to the problems this rule is trying to prevent.
|
|
Solution: Suppress warnings judiciously based on full knowledge and report reasons to suppress (false positives) to the rule maintainers so these can be fixed. (jpinpoint-rules)</description>
|
|
<priority>4</priority>
|
|
<properties>
|
|
<property name="ruleIdMatches" type="String" value=".*"
|
|
description="Regex for inclusion of rules"/>
|
|
<property name="ruleIdNotMatches" type="String" value="^$"
|
|
description="Regex for exclusion of rules"/>
|
|
<property name="version" value="2.0"/>
|
|
<property name="xpath">
|
|
<value><![CDATA[
|
|
//Annotation//Name[@Image="SuppressWarnings" or @Image="SuppressFBWarnings"]/..//Literal[(matches(@Image, $ruleIdMatches)) and not (matches(@Image, $ruleIdNotMatches))]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
</rule>
|
|
|
|
<rule name="UsingSuppressWarningsHighRisk" class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java" message="Using SuppressWarnings for a rule that is meant to prevent high risk problems." typeResolution="true"
|
|
externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Performance">
|
|
<description>(Informative) Problem: This rule detects high risk problems, suppressing them without full knowledge can lead to incidents like customer data mix-up, corrupt data, server crashes or very bad performance.
|
|
Solution: Suppress warnings judiciously based on full knowledge and report reasons to suppress (false positives) to the rule maintainers so these can be fixed. (jpinpoint-rules)</description>
|
|
<priority>4</priority>
|
|
<properties>
|
|
<property name="ruleIdMatches" type="String" value="AvoidUnguardedMutableFieldsInSharedObjects|AvoidUnguardedAssignmentToNonFinalFieldsInSharedObjects|AvoidMutableStaticFields|[^\w]ALL[^\w]|[^\w]all[^\w]|PMD[^\.]|pmd[^:]"
|
|
description="Regex for inclusion of high risk rules"/>
|
|
<property name="ruleIdNotMatches" type="String" value="^$"
|
|
description="Regex for exclusion of high risk rules"/>
|
|
<property name="version" value="2.0"/>
|
|
<property name="xpath">
|
|
<value><![CDATA[
|
|
//Annotation//Name[@Image="SuppressWarnings" or @Image="SuppressFBWarnings"]/..//Literal[(matches(@Image, $ruleIdMatches)) and not (matches(@Image, $ruleIdNotMatches))]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
</rule>
|
|
|
|
<!-- END Included file 'common.xml' -->
|
|
<!-- BEGIN Included file 'common_std.xml' -->
|
|
<rule name="AvoidApacheCommonsFileItemNonStreaming"
|
|
language="java"
|
|
message="Avoid memory intensive FileItem.get and FileItem.getString"
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
typeResolution="true"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_performance.html#AvoidApacheCommonsFileItemNonStreaming">
|
|
<description>
|
|
Problem: Use of FileItem.get and FileItem.getString could exhaust memory since they load the entire file into memory
|
|
Solution: Use streaming methods and buffering.
|
|
(jpinpoint-rules)</description>
|
|
<priority>2</priority>
|
|
<properties>
|
|
<property name="version" value="1.0"/>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//PrimaryPrefix/Name
|
|
[ends-with(@Image, '.get') or ends-with(@Image, '.getString')]
|
|
[
|
|
starts-with(@Image, concat(
|
|
ancestor::MethodDeclaration//FormalParameter/Type/ReferenceType/ClassOrInterfaceType[typeIs('org.apache.commons.fileupload.FileItem')]/../../..//VariableDeclaratorId/@Image,
|
|
'.')
|
|
) or
|
|
starts-with(@Image, concat(
|
|
ancestor::MethodDeclaration//LocalVariableDeclaration/Type/ReferenceType/ClassOrInterfaceType[typeIs('org.apache.commons.fileupload.FileItem')]/../../..//VariableDeclaratorId/@Image,
|
|
'.')
|
|
) or
|
|
starts-with(@Image, concat(
|
|
ancestor::ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/FieldDeclaration/Type/ReferenceType/ClassOrInterfaceType[typeIs('org.apache.commons.fileupload.FileItem')]/../../..//VariableDeclaratorId/@Image,
|
|
'.')
|
|
)
|
|
]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
public class FileStuff {
|
|
private String bad(FileItem fileItem) {
|
|
return fileItem.getString();
|
|
}
|
|
|
|
private InputStream good(FileItem fileItem) {
|
|
return fileItem.getInputStream();
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="AvoidCalendarDateCreation"
|
|
language="java"
|
|
message="A Calendar is used to create a Date or DateTime, this is expensive."
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
typeResolution="true"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_performance.html#AvoidCalendarDateCreation">
|
|
<description>Problem: A Calendar is a heavyweight object and expensive to create.
|
|
Solution: Use 'new Date()', Java 8+ java.time.[Local/Zoned]DateTime.now() or joda time '[Local]DateTime.now()'.
|
|
(jpinpoint-rules)</description>
|
|
<priority>2</priority>
|
|
<properties>
|
|
<property name="version" value="1.0"/>
|
|
<property name="xpath">
|
|
<value><![CDATA[
|
|
//PrimaryPrefix[Name[ends-with(@Image, 'Calendar.getInstance')]] [count(../PrimarySuffix) > 2 and ../PrimarySuffix[last()-1][@Image = 'getTime' or @Image='getTimeInMillis']]
|
|
|
|
|
//Block/BlockStatement//Expression/PrimaryExpression/
|
|
PrimaryPrefix/Name[typeIs('java.util.Calendar') and (ends-with(@Image,'.getTime') or ends-with(@Image,'.getTimeInMillis'))]
|
|
|
|
|
//ClassOrInterfaceType[typeIs('org.joda.time.DateTime') or typeIs('org.joda.time.LocalDateTime')][../Arguments/ArgumentList/Expression/PrimaryExpression/PrimaryPrefix/Name[ends-with(@Image, 'Calendar.getInstance')]]
|
|
]]></value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
public class DateStuff {
|
|
private Date bad1() {
|
|
return Calendar.getInstance().getTime(); // now
|
|
}
|
|
private Date good1a() {
|
|
return new Date(); // now
|
|
}
|
|
private LocalDateTime good1b() {
|
|
return LocalDateTime.now();
|
|
}
|
|
private long bad2() {
|
|
return Calendar.getInstance().getTimeInMillis();
|
|
}
|
|
private long good2() {
|
|
return System.currentTimeMillis();
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="AvoidConcatInAppend"
|
|
language="java"
|
|
message="Concatenation inside append. Use extra append."
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
typeResolution="true"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_performance.html#AvoidConcatInAppend">
|
|
<description>Concatenation of Strings is used inside an StringBuilder.append argument. Problem: Each statement with one or more +-operators creates a hidden temporary StringBuilder, a char[] and a new String object, which all have to be garbage collected.
|
|
Solution: Use an extra fluent append instead of concatenation.
|
|
(jpinpoint-rules)</description>
|
|
<priority>2</priority>
|
|
<properties>
|
|
<property name="version" value="1.0"/>
|
|
<property name="xpath">
|
|
<value><![CDATA[
|
|
//MethodDeclaration/Block/BlockStatement[
|
|
(.//PrimaryExpression/PrimaryPrefix/Name[substring-after(@Image, '.') = 'append']
|
|
or
|
|
.//PrimaryExpression/PrimarySuffix/@Image = 'append')
|
|
and
|
|
.//PrimaryExpression/PrimarySuffix/Arguments/ArgumentList/Expression[1]/AdditiveExpression[@Image='+'
|
|
and (count(PrimaryExpression/PrimaryPrefix/Name) > 0)
|
|
and not(PrimaryExpression/PrimaryPrefix/Name/@Image=
|
|
ancestor::ClassOrInterfaceBody//FieldDeclaration[@Final='true']//VariableDeclaratorId/@Image)
|
|
and not(PrimaryExpression/PrimaryPrefix/Name/@Image=
|
|
ancestor::Block//LocalVariableDeclaration[@Final='true']//VariableDeclaratorId/@Image)
|
|
]]
|
|
]]></value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
public class StringStuff {
|
|
private String bad(String arg) {
|
|
StringBuilder sb = new StringBuilder();
|
|
sb.append("arg='" + arg + "'");
|
|
return sb.toString();
|
|
}
|
|
|
|
private String good(String arg) {
|
|
StringBuilder sb = new StringBuilder();
|
|
sb.append("arg='").append(arg).append("'");
|
|
return sb.toString();
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="AvoidConcatInLoop"
|
|
language="java"
|
|
message="A String is concatenated in a loop. Use StringBuilder.append."
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
typeResolution="true"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_performance.html#AvoidConcatInLoop">
|
|
<description>A String is built in a loop by concatenation. Problem: Each statement with one or more +-operators creates a hidden temporary StringBuilder, a char[] and a new String object, which all have to be garbage collected.
|
|
Solution: Use the StringBuilder append method.
|
|
(jpinpoint-rules)</description>
|
|
<priority>2</priority>
|
|
<properties>
|
|
<property name="version" value="2.0"/>
|
|
<property name="xpath">
|
|
<value><![CDATA[
|
|
(//ForStatement | //WhileStatement | //DoStatement)//AssignmentOperator[
|
|
(: a += ...; -- a being a string :)
|
|
@Image='+=' and preceding-sibling::*[1]/PrimaryPrefix/Name[pmd-java:typeIs('java.lang.String')]
|
|
|
|
(: a = ... + a + ...; -- a being a string :)
|
|
or @Image='=' and following-sibling::*[1]/AdditiveExpression/PrimaryExpression/PrimaryPrefix/Name[
|
|
pmd-java:typeIs('java.lang.String')
|
|
and @Image = ancestor::StatementExpression/PrimaryExpression/PrimaryPrefix/Name/@Image
|
|
]
|
|
]/.. (: Go up to report on the StatementExpression :)
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
public class StringStuff {
|
|
private String bad(String arg) {
|
|
String log = "";
|
|
List<String> values = Arrays.asList("tic ", "tac ", "toe ");
|
|
for (String val : values) {
|
|
log += val;
|
|
}
|
|
return log;
|
|
}
|
|
|
|
private String good(String arg) {
|
|
StringBuilder sb = new StringBuilder();
|
|
List<String> values = Arrays.asList("tic ", "tac ", "toe ");
|
|
for (String val : values) {
|
|
sb.append(val);
|
|
}
|
|
return sb.toString();
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<!-- END Included file 'common_std.xml' -->
|
|
<!-- BEGIN Included file 'concurrent.xml' -->
|
|
<rule name="AvoidCompletionServiceTake"
|
|
message="Avoid completionService.take, use poll"
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java"
|
|
typeResolution="true" externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Performance#JavaCodePerformance">
|
|
<description>
|
|
Problem: take() stalls indefinitely in case of hanging threads and consumes a thread.
|
|
Solution: use poll() with a timeout value and handle the timeout.
|
|
(jpinpoint-rules)</description>
|
|
<priority>2</priority>
|
|
<properties>
|
|
<property name="version" value="1.0"/>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//MethodDeclaration//PrimaryPrefix/Name[ends-with(@Image, '.take')]
|
|
[(starts-with(@Image, concat(ancestor::MethodDeclaration//FormalParameter/Type/ReferenceType/ClassOrInterfaceType[
|
|
typeIs('java.util.concurrent.CompletionService')
|
|
or typeIs('java.util.concurrent.ExecutorCompletionService')
|
|
]/../../../VariableDeclaratorId/@Image, '.'))
|
|
or
|
|
starts-with(@Image, concat(ancestor::MethodDeclaration//LocalVariableDeclaration/Type/ReferenceType/ClassOrInterfaceType[
|
|
typeIs('java.util.concurrent.CompletionService')
|
|
or typeIs('java.util.concurrent.ExecutorCompletionService')
|
|
]/../../../VariableDeclarator/VariableDeclaratorId/@Image, '.'))
|
|
or
|
|
starts-with(@Image, concat(ancestor::ClassOrInterfaceBody//FieldDeclaration/Type/ReferenceType/ClassOrInterfaceType[
|
|
typeIs('java.util.concurrent.CompletionService')
|
|
or typeIs('java.util.concurrent.ExecutorCompletionService')
|
|
]/../../../VariableDeclarator/VariableDeclaratorId/@Image, '.')))
|
|
] ]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
</rule>
|
|
|
|
<rule name="AvoidFutureGetWithoutTimeout"
|
|
message="Avoid future.get without timeout"
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java"
|
|
typeResolution="true" externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Performance#JavaCodePerformance">
|
|
<description>
|
|
Problem: Stalls indefinitely in case of hanging threads and consumes a thread.
|
|
Solution: Provide a timeout value and handle the timeout.
|
|
(jpinpoint-rules)</description>
|
|
<priority>2</priority>
|
|
<properties>
|
|
<property name="version" value="2.0"/>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//MethodDeclaration//PrimaryPrefix/Name[ends-with(@Image, '.get')]
|
|
(: future.get or variant called on formal param :)
|
|
[(exists(index-of((ancestor::MethodDeclaration//FormalParameter[
|
|
pmd-java:typeIs('java.util.concurrent.Future')
|
|
or pmd-java:typeIs('java.util.concurrent.CompletableFuture')
|
|
or pmd-java:typeIs('java.util.concurrent.Response')
|
|
or pmd-java:typeIs('java.util.concurrent.RunnableFuture')
|
|
or pmd-java:typeIs('java.util.concurrent.RunnableScheduledFuture')
|
|
or pmd-java:typeIs('java.util.concurrent.ScheduledFuture')
|
|
]/VariableDeclaratorId/@Image), substring-before(@Image,'.')))
|
|
or
|
|
(: future.get or variant called on local var :)
|
|
exists(index-of((ancestor::MethodDeclaration//LocalVariableDeclaration/Type[
|
|
pmd-java:typeIs('java.util.concurrent.Future')
|
|
or pmd-java:typeIs('java.util.concurrent.CompletableFuture')
|
|
or pmd-java:typeIs('java.util.concurrent.Response')
|
|
or pmd-java:typeIs('java.util.concurrent.RunnableFuture')
|
|
or pmd-java:typeIs('java.util.concurrent.RunnableScheduledFuture')
|
|
or pmd-java:typeIs('java.util.concurrent.ScheduledFuture')
|
|
]/../VariableDeclarator/VariableDeclaratorId/@Image), substring-before(@Image,'.')))
|
|
or
|
|
(: future.get or variant called on field :)
|
|
exists(index-of((ancestor::ClassOrInterfaceBody//FieldDeclaration[
|
|
pmd-java:typeIs('java.util.concurrent.Future')
|
|
or pmd-java:typeIs('java.util.concurrent.CompletableFuture')
|
|
or pmd-java:typeIs('java.util.concurrent.Response')
|
|
or pmd-java:typeIs('java.util.concurrent.RunnableFuture')
|
|
or pmd-java:typeIs('java.util.concurrent.RunnableScheduledFuture')
|
|
or pmd-java:typeIs('java.util.concurrent.ScheduledFuture')
|
|
]/VariableDeclarator/VariableDeclaratorId/@Image), substring-before(@Image,'.')))
|
|
)
|
|
(: .get without arguments :)
|
|
and not(../../PrimarySuffix/Arguments/ArgumentList)
|
|
]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
public static String bad(CompletableFuture<String> complFuture) throws Exception {
|
|
return complFuture.get(); // bad
|
|
}
|
|
|
|
public static String good(CompletableFuture<String> complFuture) throws Exception {
|
|
return complFuture.get(10, TimeUnit.SECONDS); // good
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="AvoidMutableStaticFields"
|
|
message="Avoid non-final or mutable static fields. Make final immutable or access thread-safely and use @GuardedBy."
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java"
|
|
typeResolution="true" externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Performance#JavaCodePerformance-TUTC08">
|
|
<description>
|
|
Problem: Multiple threads typically access static fields. Unguarded assignment to a mutable or non-final static field is thread-unsafe and may cause corruption or visibility problems. To make this thread-safe, that is, guard the field e.g. with synchronized methods, may cause contention.
|
|
Solution: Make the fields final and unmodifiable. If they really need to be mutable, make access thread-safe: use synchronized and @GuardedBy or use volatile. Consider lock contention.
|
|
(jpinpoint-rules)</description>
|
|
<priority>2</priority>
|
|
<properties>
|
|
<property name="version" value="2.0"/>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
(: static field, non-final, non-volatile, non-guarded by :)
|
|
//ClassOrInterfaceDeclaration/ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/FieldDeclaration
|
|
[@Static=true() and @Final=false() and @Volatile=false() and not (../Annotation//Name[@Image='GuardedBy'])]
|
|
,
|
|
(: static field, non-guarded, some often used known mutable types, declaration side :)
|
|
(//ClassOrInterfaceDeclaration/ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/FieldDeclaration[@Static=true()]/Type/ReferenceType/ClassOrInterfaceType[
|
|
(((pmd-java:typeIs('java.util.Date') or pmd-java:typeIs('java.lang.StringBuilder') or pmd-java:typeIs('java.lang.StringBuffer') or pmd-java:typeIs('java.net.URL')) or pmd-java:typeIs('java.io.File'))
|
|
or (ancestor::FieldDeclaration/VariableDeclarator/VariableInitializer[ArrayInitializer and count(ArrayInitializer/VariableInitializer) > 0]))
|
|
and not (ancestor::ClassOrInterfaceBodyDeclaration/Annotation//Name[@Image='GuardedBy'])
|
|
])
|
|
,
|
|
(: static field, non-guarded, some often used known collection/array types, allocation side:)
|
|
(//ClassOrInterfaceDeclaration/ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/FieldDeclaration[@Static=true() and not (../Annotation//Name[@Image='GuardedBy'])]/
|
|
VariableDeclarator/VariableInitializer[((ArrayInitializer and count(ArrayInitializer/VariableInitializer) > 0)
|
|
or Expression/PrimaryExpression/PrimaryPrefix/AllocationExpression[ArrayDimsAndInits and xs:int(ArrayDimsAndInits and (xs:int(ArrayDimsAndInits/Expression//Literal/@Image) > 0 or ArrayDimsAndInits/Expression//Name))]
|
|
or Expression/PrimaryExpression/PrimaryPrefix/AllocationExpression[(pmd-java:typeIs('java.util.ArrayList') or pmd-java:typeIs('java.util.HashMap') or pmd-java:typeIs('java.util.HashSet'))]
|
|
or Expression/PrimaryExpression/PrimaryPrefix/Name[@Image='Arrays.asList']
|
|
)])
|
|
,
|
|
(: static-block allocations of non-empty arrays :)
|
|
//Initializer//AllocationExpression[((ArrayDimsAndInits and ((xs:int(ArrayDimsAndInits/Expression//Literal/@Image) > 0) or exists(ArrayDimsAndInits/Expression//Name) or exists(ArrayDimsAndInits/ArrayInitializer//Expression)))
|
|
or
|
|
(: static-block allocations of known mutable types :)
|
|
ClassOrInterfaceType[pmd-java:typeIs('java.util.ArrayList') or pmd-java:typeIs('java.util.HashMap') or pmd-java:typeIs('java.util.HashSet')])
|
|
and
|
|
(: given the field is not @GuardedBy :)
|
|
ancestor::StatementExpression/PrimaryExpression/PrimaryPrefix/Name/@Image = ancestor::ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration[count(Annotation//Name[@Image='GuardedBy']) = 0]/FieldDeclaration//VariableDeclaratorId/@Image
|
|
]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
</rule>
|
|
|
|
<rule name="AvoidThreadUnsafeJaxbUsage" message="A JAXB Marshaller, Unmarshaller or Validator is used in a thread-unsafe way." class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java" typeResolution="true" externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Performance#JavaCodePerformance-IUOXAR07">
|
|
<description>Problem: JAXB Marshaller, Unmarshaller and Validator are not thread-safe.
|
|
Solution: Create a new instance every time you need to marshall, unmarshall or validate a document.
|
|
(jpinpoint-rules)</description>
|
|
<priority>1</priority>
|
|
<properties>
|
|
<property name="version" value="1.0"/>
|
|
<property name="xpath">
|
|
<value><![CDATA[
|
|
//FieldDeclaration/Type/ReferenceType/ClassOrInterfaceType[typeIs('javax.xml.bind.Marshaller')]
|
|
|
|
|
//FieldDeclaration/Type/ReferenceType/ClassOrInterfaceType[typeIs('javax.xml.bind.Unmarshaller')]
|
|
|
|
|
//FieldDeclaration/Type/ReferenceType/ClassOrInterfaceType[typeIs('javax.xml.bind.Validator')]
|
|
|
|
|
//FieldDeclaration/Type/ReferenceType/ClassOrInterfaceType[typeIs('javax.xml.validation.Validator')]
|
|
]]></value>
|
|
</property>
|
|
</properties>
|
|
</rule>
|
|
|
|
<rule name="AvoidUnguardedAssignmentToNonFinalFieldsInObjectsUsingSynchronized"
|
|
message="Avoid unguarded assignments to non-final fields in objects using synchronized. Access thread-safely and use @GuardedBy."
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java"
|
|
typeResolution="true" externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Performance#JavaCodePerformance-TUTC07">
|
|
<description>
|
|
Problem: Multiple threads typically access fields of an object using synchronized. Unguarded assignment to a non-final field is thread-unsafe and may cause corruption or visibility problems. To make this thread-safe, that is, guard the field e.g. with synchronized methods, may cause contention.
|
|
Solution: Make the fields final and unmodifiable. If they really need to be mutable, make access thread-safe: use synchronized and jcip @GuardedBy or use volatile.
|
|
Notes
|
|
1. In case you are sure the class is used in single threaded context only, remove current use of synchronized and annotate the class with @NotThreadSafe to make this explicit.
|
|
2. Use package-private and @VisibleForTesting for methods (e.g. setters) used for JUnit only.
|
|
(jpinpoint-rules)</description>
|
|
<priority>2</priority>
|
|
<properties>
|
|
<property name="version" value="2.0"/>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
(: if @NotThreadSafe no checking :)
|
|
//TypeDeclaration[count(Annotation/MarkerAnnotation/Name[@Image='NotThreadSafe'])=0]
|
|
(: non-static classes using synchronized :)
|
|
//ClassOrInterfaceDeclaration[@Static=false()]/ClassOrInterfaceBody[//SynchronizedStatement or //MethodDeclaration[@Synchronized=true()]]
|
|
(: assignment to a field :)
|
|
/ClassOrInterfaceBodyDeclaration/MethodDeclaration/Block/BlockStatement/Statement//StatementExpression/AssignmentOperator/../PrimaryExpression//*[@Image=
|
|
(: non-final, non-volatile, non-GuardedBy fields :)
|
|
ancestor::ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/FieldDeclaration[@Final=false() and @Volatile=false() and not (../Annotation//Name[@Image='GuardedBy'])]/VariableDeclarator/VariableDeclaratorId/@Image
|
|
(: field not on accessor method with assignment, annotated with framework annotation :)
|
|
and not (ancestor::ClassOrInterfaceBodyDeclaration/Annotation//Name[@Image='Autowired' or @Image='PostConstruct' or @Image='BeforeStep' or @Image='Value' or @Image='Inject']
|
|
(: field not assigned in non-public accessor method annotated with VisibleForTesting :)
|
|
or (ancestor::ClassOrInterfaceBodyDeclaration/Annotation//Name[@Image='VisibleForTesting'] and ancestor::MethodDeclaration[@Public=false()]))]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
</rule>
|
|
|
|
<rule name="AvoidUnguardedAssignmentToNonFinalFieldsInSharedObjects"
|
|
message="Avoid unguarded assignments to non-final fields in objects shared among threads. Access thread-safely and use @GuardedBy."
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java"
|
|
typeResolution="true" externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Performance#JavaCodePerformance-TUTC07">
|
|
<description>
|
|
Problem: Multiple threads typically access fields of a singleton or may access fields in session scoped objects. Unguarded assignment to a non-final field is thread-unsafe and may cause corruption or visibility problems. To make this thread-safe, that is, guard the field e.g. with synchronized methods, may cause contention.
|
|
Solution: Make the fields final and unmodifiable. If they really need to be mutable, make access thread-safe: use synchronized and jcip @GuardedBy or use volatile.
|
|
Notes
|
|
1. Autowiring/injection is thread safe, yet make sure no other thread-unsafe assignment is made to that field.
|
|
2. In case you are sure the Component is used in single threaded context only (e.g. a Tasklet), annotate the class with @NotThreadSafe to make this explicit.
|
|
3. Use package-private and @VisibleForTesting for methods (e.g. setters) used for JUnit only.
|
|
(jpinpoint-rules)</description>
|
|
<priority>2</priority>
|
|
<properties>
|
|
<property name="version" value="2.0"/>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//TypeDeclaration/Annotation//Name[(@Image='Component' or @Image='Service' or @Image='Controller' or @Image='Repository' or
|
|
(@Image='Singleton' and ancestor::TypeDeclaration/Annotation/NormalAnnotation/MemberValuePairs//Name[@Image='ConcurrencyManagementType.BEAN']))
|
|
and not (ancestor::TypeDeclaration/Annotation//Name[@Image='Scope']/..//Literal[@Image='"request"' or @Image='"prototype"'])
|
|
and not (ancestor::TypeDeclaration/Annotation//Name[@Image='RequestScope'])
|
|
(: if @NotThreadSafe no checking :)
|
|
and not (ancestor::TypeDeclaration/Annotation/MarkerAnnotation/Name[@Image='NotThreadSafe'])
|
|
(: no checking if @ConfigurationProperties and no @Setter :)
|
|
and not ((ancestor::TypeDeclaration/Annotation//Name[@Image='ConfigurationProperties'])
|
|
and not (ancestor::TypeDeclaration/Annotation/MarkerAnnotation/Name[@Image='Setter']))]
|
|
(: assignment to a field :)
|
|
/../../..//ClassOrInterfaceDeclaration[@Static=false()]/ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/MethodDeclaration/Block/BlockStatement/Statement//StatementExpression/AssignmentOperator/../PrimaryExpression//*[@Image=
|
|
(: non-final, non-volatile, non-GuardedBy fields :)
|
|
ancestor::ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/FieldDeclaration[@Final=false() and @Volatile=false() and not (../Annotation//Name[@Image='GuardedBy'])]/VariableDeclarator/VariableDeclaratorId/@Image
|
|
(: field not on accessor method with assignment, annotated with framework annotation :)
|
|
and not (ancestor::ClassOrInterfaceBodyDeclaration/Annotation//Name[@Image='Autowired' or @Image='PostConstruct' or @Image='BeforeStep' or @Image='Value' or @Image='Inject']
|
|
(: field not assigned in non-public accessor method annotated with VisibleForTesting :)
|
|
or (ancestor::ClassOrInterfaceBodyDeclaration/Annotation//Name[@Image='VisibleForTesting'] and ancestor::MethodDeclaration[@Public=false()]))]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
</rule>
|
|
|
|
<rule name="AvoidUnguardedMutableFieldsInObjectsUsingSynchronized"
|
|
message="Avoid unguarded non-final or mutable fields in objects using synchronized. Make final immutable or access thread-safely and use @GuardedBy."
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java"
|
|
typeResolution="true" externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Performance#JavaCodePerformance-TUTC07">
|
|
<description>
|
|
Problem: Multiple threads typically access fields of an object using synchronized. If a field or its reference is mutable, access is thread-unsafe and may cause corruption or visibility problems. To make this thread-safe, that is, guard the field e.g. with synchronized methods, may cause contention.
|
|
Solution: Make the fields final and unmodifiable. If they really need to be mutable, make access thread-safe: use synchronized and jcip @GuardedBy or use volatile.
|
|
Notes
|
|
1. Instances of Date, StringBuilder, URL and File are examples of mutable objects and should be avoided (or else guarded) as fields of shared objects. In case mutable fields are final and not modified after initialization (read-only) they are thread safe, however any modification to it is thread-unsafe. Since field modification is easily coded, avoid this situation.
|
|
2. Instances of classes like ArrayList, HashMap and HashSet are also mutable and should be properly wrapped with e.g. Collections.unmodifiableList after initialization (see TUTC03), or accessed thread-safely with e.g. Collections.synchronizedList or thread-safe implementations like ConcurrentHashMap.
|
|
3. Autowiring/injection is thread safe, yet make sure no other thread-unsafe assignment is made to that field.
|
|
4. In case you are sure the class is used in single threaded context only, annotate the class with @NotThreadSafe to make this explicit.
|
|
5. Use package private and @VisibleForTesting for methods used for JUnit only.
|
|
(jpinpoint-rules)</description>
|
|
<priority>3</priority>
|
|
<properties>
|
|
<property name="version" value="2.0"/>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
(: if @NotThreadSafe no checking :)
|
|
//TypeDeclaration[count(Annotation/MarkerAnnotation/Name[@Image='NotThreadSafe'])=0]
|
|
(: non-static classes using synchronized :)
|
|
//ClassOrInterfaceDeclaration[@Static=false()]/ClassOrInterfaceBody[//SynchronizedStatement or //MethodDeclaration[@Synchronized=true()]]
|
|
(: non-final and non-volatile fields :)
|
|
/ClassOrInterfaceBodyDeclaration/FieldDeclaration[@Final=false() and @Volatile=false()
|
|
(: field not annotated with framework annotation or GuardedBy :)
|
|
and not (../Annotation//Name[@Image='Autowired' or @Image='PersistenceContext' or @Image='EJB' or @Image='Resource' or @Image='Inject' or @Image='Value' or @Image='GuardedBy'])
|
|
(: field not on accessor method with assignment, annotated with framework annotation :)
|
|
and not (../../ClassOrInterfaceBodyDeclaration/Annotation//Name[@Image='Autowired' or @Image='PostConstruct' or @Image='BeforeStep' or @Image='Value' or @Image='Inject']
|
|
/../../..//BlockStatement/Statement//StatementExpression/AssignmentOperator/../PrimaryExpression//@Image=
|
|
./VariableDeclarator/VariableDeclaratorId/@Image)
|
|
(: or field of known mutable types including array :)
|
|
or ((Type/ReferenceType/ClassOrInterfaceType[(pmd-java:typeIs('java.util.Date') or pmd-java:typeIs('java.lang.StringBuilder') or pmd-java:typeIs('java.lang.StringBuffer') or pmd-java:typeIs('java.net.URL') or pmd-java:typeIs('java.io.File')) or
|
|
(ancestor::FieldDeclaration/VariableDeclarator/VariableInitializer[ArrayInitializer and count(ArrayInitializer/VariableInitializer) > 0])])
|
|
(: or in-line allocation of known mutable collection types :)
|
|
or (VariableDeclarator/VariableInitializer/Expression/PrimaryExpression/PrimaryPrefix/AllocationExpression/ClassOrInterfaceType[pmd-java:typeIs('java.util.ArrayList') or pmd-java:typeIs('java.util.HashMap') or pmd-java:typeIs('java.util.HashSet')] )
|
|
(: or in-constructor allocation of known mutable collection types :)
|
|
or (VariableDeclarator/VariableDeclaratorId/@Image = ancestor::ClassOrInterfaceBody//ConstructorDeclaration//StatementExpression/Expression[pmd-java:typeIs('java.util.ArrayList') or pmd-java:typeIs('java.util.HashMap') or pmd-java:typeIs('java.util.HashSet')]/../..//Name/@Image)
|
|
(: mutable types not annotated with GuardedBy :)
|
|
) and not (../Annotation//Name[@Image='GuardedBy'])
|
|
]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
</rule>
|
|
|
|
<rule name="AvoidUnguardedMutableFieldsInSharedObjects"
|
|
message="Avoid unguarded non-final or mutable fields in objects shared among threads. Make final immutable or access thread-safely and use @GuardedBy."
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java"
|
|
typeResolution="true" externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Performance#JavaCodePerformance-TUTC07">
|
|
<description>
|
|
Problem: Multiple threads typically access fields of a singleton or may access fields in session scoped objects. If a field or its reference is mutable, access is thread-unsafe and may cause corruption or visibility problems. To make this thread-safe, that is, guard the field e.g. with synchronized methods, may cause contention.
|
|
Solution: Make the fields final and unmodifiable. If they really need to be mutable, make access thread-safe: use synchronized and jcip @GuardedBy or use volatile.
|
|
Notes
|
|
1. Instances of Date, StringBuilder, URL and File are examples of mutable objects and should be avoided (or else guarded) as fields of shared objects. In case mutable fields are final and not modified after initialization (read-only) they are thread safe, however any modification to it is thread-unsafe. Since field modification is easily coded, avoid this situation.
|
|
2. Instances of classes like ArrayList, HashMap and HashSet are also mutable and should be properly wrapped with e.g. Collections.unmodifiableList after initialization (see TUTC03), or accessed thread-safely with e.g. Collections.synchronizedList or thread-safe implementations like ConcurrentHashMap.
|
|
3. Autowiring/injection is thread safe, yet make sure no other thread-unsafe assignment is made to that field.
|
|
4. In case you are sure the Component is used in single threaded context only (e.g. a Tasklet), annotate the class with @NotThreadSafe to make this explicit.
|
|
5. Use package private and @VisibleForTesting for methods used for JUnit only.
|
|
(jpinpoint-rules)</description>
|
|
<priority>2</priority>
|
|
<properties>
|
|
<property name="version" value="2.0"/>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
(: known assumed singleton types by annotation :)
|
|
//TypeDeclaration/Annotation//Name[(@Image='Component' or @Image='Service' or @Image='Controller' or @Image='Repository' or
|
|
(@Image='Singleton' and ancestor::TypeDeclaration/Annotation/NormalAnnotation/MemberValuePairs//Name[@Image='ConcurrencyManagementType.BEAN']))
|
|
(: not shared when request or prototype scope :)
|
|
and not (ancestor::TypeDeclaration/Annotation//Name[@Image='Scope']/..//Literal[@Image='"request"' or @Image='"prototype"'])
|
|
and not (ancestor::TypeDeclaration/Annotation//Name[@Image='RequestScope'])
|
|
(: if @NotThreadSafe no checking :)
|
|
and not (ancestor::TypeDeclaration/Annotation/MarkerAnnotation/Name[@Image='NotThreadSafe'])
|
|
(: ConfigurationProperties assumed executed only once, no violation, except if Lombok Setter :)
|
|
and not ((ancestor::TypeDeclaration/Annotation//Name[@Image='ConfigurationProperties'])
|
|
and not (ancestor::TypeDeclaration/Annotation/MarkerAnnotation/Name[@Image='Setter']))]
|
|
(: non-final and non-volatile fields :)
|
|
/../../..//ClassOrInterfaceDeclaration[@Static=false()]/ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/FieldDeclaration[@Final=false() and @Volatile=false()
|
|
(: field not annotated with framework annotation or GuardedBy :)
|
|
and not (../Annotation//Name[@Image='Autowired' or @Image='PersistenceContext' or @Image='EJB' or @Image='Resource' or @Image='Inject' or @Image='Value' or @Image='GuardedBy'])
|
|
(: field not on accessor method with assignment level annotated with framework annotation :)
|
|
and not (../../ClassOrInterfaceBodyDeclaration/Annotation//Name[@Image='Autowired' or @Image='PostConstruct' or @Image='BeforeStep' or @Image='Value' or @Image='Inject']
|
|
/../../..//BlockStatement/Statement//StatementExpression/AssignmentOperator/../PrimaryExpression//@Image=
|
|
./VariableDeclarator/VariableDeclaratorId/@Image)
|
|
(: or field of known mutable types including array :)
|
|
or ((Type/ReferenceType/ClassOrInterfaceType[(pmd-java:typeIs('java.util.Date') or pmd-java:typeIs('java.lang.StringBuilder') or pmd-java:typeIs('java.lang.StringBuffer') or pmd-java:typeIs('java.net.URL') or pmd-java:typeIs('java.io.File')) or
|
|
(ancestor::FieldDeclaration/VariableDeclarator/VariableInitializer[ArrayInitializer and count(ArrayInitializer/VariableInitializer) > 0])])
|
|
(: or in-line allocation of known mutable collection types :)
|
|
or (VariableDeclarator/VariableInitializer/Expression/PrimaryExpression/PrimaryPrefix/AllocationExpression[pmd-java:typeIs('java.util.ArrayList') or pmd-java:typeIs('java.util.HashMap') or pmd-java:typeIs('java.util.HashSet')] )
|
|
(: or in-constructor allocation of known mutable collection types :)
|
|
or (VariableDeclarator/VariableDeclaratorId/@Image = ancestor::ClassOrInterfaceBody//ConstructorDeclaration//StatementExpression/Expression[pmd-java:typeIs('java.util.ArrayList') or pmd-java:typeIs('java.util.HashMap') or pmd-java:typeIs('java.util.HashSet')]/../..//Name/@Image)
|
|
(: not annotated GuardedBy :)
|
|
)
|
|
and not (../Annotation//Name[@Image='GuardedBy'])
|
|
]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
</rule>
|
|
|
|
<rule name="NotProperlySynchronizingOnThisWhileUsingGuardedBy"
|
|
message="Not properly synchronizing access of field while using @GuardedBy('this')"
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java"
|
|
typeResolution="true" externalInfoUrl="https://jcip.net/annotations/doc/index.html">
|
|
<description>
|
|
Problem: The field to which this annotation is applied should only be accessed when holding the built-in 'this' lock by using synchronized.
|
|
Solution: Make access thread-safe: synchronize access by method modifier or a synchronized(this) block.
|
|
Note that methods with annotations @Autowired, @PostConstruct, @BeforeStep, @Value and @Inject are ignored.
|
|
(jpinpoint-rules)</description>
|
|
<priority>3</priority>
|
|
<properties>
|
|
<property name="version" value="2.0"/>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//MethodDeclaration[@Synchronized=false()
|
|
and not (../Annotation//Name[@Image='Autowired' or @Image='PostConstruct' or @Image='BeforeStep' or @Image='Value' or @Image='Inject'])]
|
|
//PrimaryPrefix/Name[substring-before(concat(@Image,'.'), '.') =
|
|
ancestor::ClassOrInterfaceBody//Annotation//Name[@Image='GuardedBy']/..//Literal[@Image='"this"']/
|
|
ancestor::ClassOrInterfaceBodyDeclaration/FieldDeclaration//VariableDeclaratorId/@Image
|
|
and (
|
|
not (ancestor::SynchronizedStatement)
|
|
or ancestor::SynchronizedStatement/Expression//Name)]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
class Bad1 {
|
|
@GuardedBy("this")
|
|
private String txt;
|
|
|
|
public String getText() { return txt; } // bad
|
|
public void setText(String t) { txt = t; } // bad
|
|
}
|
|
|
|
class Good1 {
|
|
@GuardedBy("this")
|
|
private String txt;
|
|
|
|
public synchronized String getText() { return txt; }
|
|
public synchronized void setText(String t) { txt = t; }
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<!-- END Included file 'concurrent.xml' -->
|
|
<!-- BEGIN Included file 'spring.xml' -->
|
|
<rule name="AvoidExpressionsInCacheable" class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java" message="Avoid SpEL-expression for computing Cacheable key" typeResolution="true"
|
|
externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Performance#JavaCodePerformance-TMSU12">
|
|
<description>Spring Expression Language (SpEL) expression is used for computing the key dynamically. Problem: evaluating the expression language is expensive, on every call.
|
|
Solution: use a custom KeyGenerator: keyGenerator=... instead of key=...
|
|
(jpinpoint-rules)</description>
|
|
<priority>2</priority>
|
|
<properties>
|
|
<property name="version" value="1.0"/>
|
|
<property name="xpath">
|
|
<value><![CDATA[
|
|
//ClassOrInterfaceBodyDeclaration//Annotation/NormalAnnotation[Name/@Image='Cacheable']/MemberValuePairs/MemberValuePair[@MemberName='key']
|
|
]]></value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
class Bad1 {
|
|
@Cacheable(value = "Cache1", key = "#key1") // bad
|
|
public String bad1(final String key1) {
|
|
return getRemote(key1);
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="AvoidImproperAnnotationCombinations"
|
|
language="java"
|
|
message="Don't combine these annotations"
|
|
externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Performance#JavaCodePerformance-Annotations"
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule">
|
|
<description>
|
|
Improper combination of annotations. Problem: these annotations are not meant to be combined and may cause unexpected and unwanted behavior.
|
|
Solution: remove the inappropriate annotation.
|
|
Don't combine 2+ of [@Component, @Service, @Configuration, @Controller, @Repository, @Entity] (Spring/JPA)
|
|
Don't combine [@Data with @Value] and [@Data or @Value] with any of [@ToString, @EqualsHashCode, @Getter, @Setter, @RequiredArgsConstructor] (Lombok)
|
|
(jpinpoint-rules)</description>
|
|
<priority>2</priority>
|
|
<properties>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//TypeDeclaration[count(./Annotation/MarkerAnnotation/Name[@Image='Component' or @Image='Service' or @Image='Configuration' or @Image='Controller' or @Image='Repository' or @Image='Entity']) > 1]
|
|
|
|
|
//ClassOrInterfaceBodyDeclaration[count(./Annotation/MarkerAnnotation/Name[@Image='Component' or @Image='Service' or @Image='Configuration' or @Image='Controller' or @Image='Repository' or @Image='Entity']) > 1]
|
|
|
|
|
//TypeDeclaration[count(./Annotation/MarkerAnnotation/Name[@Image='Data' or @Image='Value']) > 1]
|
|
|
|
|
//ClassOrInterfaceBodyDeclaration[count(./Annotation/MarkerAnnotation/Name[@Image='Data' or @Image='Value']) > 1]
|
|
|
|
|
//TypeDeclaration[./Annotation/MarkerAnnotation/Name[@Image='Data' or @Image='Value'] and ./Annotation/MarkerAnnotation/Name[@Image='ToString' or @Image='EqualsAndHashCode' or @Image='Getter' or @Image='Setter' or @Image='RequiredArgsConstructor']]
|
|
|
|
|
//ClassOrInterfaceBodyDeclaration[./Annotation/MarkerAnnotation/Name[@Image='Data' or @Image='Value'] and ./Annotation/MarkerAnnotation/Name[@Image='ToString' or @Image='EqualsAndHashCode' or @Image='Getter' or @Image='Setter' or @Image='RequiredArgsConstructor']]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
</rule>
|
|
|
|
<rule name="AvoidModelMapAsRenderParameter" class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java" message="A ModelMap or @ModelAttribute is used as parameter of a portlet render method and implicitely put in the session." typeResolution="true"
|
|
externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Performance#JavaCodePerformance-TMSU11">
|
|
<description>Problem: ModelMaps are rather large objects containing explicitly added data and administrative data from Spring. They are added to the Portlet session implicitly. They stay in the session for some time: during session activity and 30 minutes (HTTP timeout) after it, in case the user does not exit explicitly. They occupy heap space during that time, for every user.
|
|
Solution: Remove the ModelMap from the render method parameter list and create a new local ModelMap to use in the render request scope.
|
|
(jpinpoint-rules)</description>
|
|
<priority>2</priority>
|
|
<properties>
|
|
<property name="version" value="1.0"/>
|
|
<property name="xpath">
|
|
<value><![CDATA[
|
|
//ClassOrInterfaceBodyDeclaration
|
|
[MethodDeclaration[@Public='true'] and
|
|
(MethodDeclaration/MethodDeclarator/FormalParameters/FormalParameter/Type/ReferenceType/ClassOrInterfaceType[typeIs('org.springframework.ui.ModelMap')] or
|
|
MethodDeclaration/MethodDeclarator/FormalParameters/FormalParameter/Annotation/MarkerAnnotation/Name[@Image='ModelAttribute']) and
|
|
(MethodDeclaration/MethodDeclarator/FormalParameters/FormalParameter/Type/ReferenceType/ClassOrInterfaceType[typeIs('javax.portlet.RenderRequest') or typeIs('javax.portlet.PortletRequest')] or
|
|
Annotation//Name[@Image='RenderMapping'])]
|
|
]]></value>
|
|
</property>
|
|
</properties>
|
|
</rule>
|
|
|
|
<rule name="AvoidSpringApplicationContextRecreation"
|
|
message="Avoid re-creation of Spring application context"
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java"
|
|
typeResolution="true" externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Performance#JavaCodePerformance-EUOCS01">
|
|
<description>
|
|
Problem: When a XXXApplicationContext is created, all Spring beans are initialized, wired and component scanning may take place. Component scanning involves extensive class path scanning which is expensive.
|
|
Solution: Create the ApplicationContext only once in the application deployed/live time.
|
|
(jpinpoint-rules)</description>
|
|
<properties>
|
|
<property name="version" value="2.0"/>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//TypeDeclaration/ClassOrInterfaceDeclaration/ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration
|
|
/MethodDeclaration//PrimaryExpression/PrimaryPrefix/AllocationExpression/ClassOrInterfaceType[ends-with(@Image, 'ApplicationContext')
|
|
and (
|
|
//ImportDeclaration/Name[starts-with(@Image, 'org.springframework.context')]
|
|
)]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<priority>2</priority>
|
|
</rule>
|
|
|
|
<rule name="AvoidSpringMVCMemoryLeaks" class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java"
|
|
message="Spring Controller returns an additive expression or a ModelAndView object which may cause a MemoryLeak" typeResolution="true"
|
|
externalInfoUrl="https://www.jpinpoint.com/doc/Java+Code+Performance">
|
|
<description>Avoid to return an additive expression for a Spring Controller because it may cause a MemoryLeak.
|
|
Each new value returned will create a new entry in the View Cache.
|
|
Also avoid to return a ModelAndView object created using non-static and non-final methods because it may
|
|
cause a MemoryLeak.
|
|
Solution: Although multiple solutions exist you can make use of model attributes icw a redirectUrl like
|
|
redirect:/redirectUrl?someAttribute={someAttribute}.(jpinpoint-rules)</description>
|
|
<priority>2</priority>
|
|
<properties>
|
|
<property name="version" value="1.0"/>
|
|
<property name="xpath">
|
|
<value><![CDATA[
|
|
(
|
|
//Statement/ReturnStatement
|
|
[Expression/AdditiveExpression]
|
|
[ancestor::ClassOrInterfaceBodyDeclaration/Annotation/NormalAnnotation/Name[starts-with(@Image,'RequestMapping')]]
|
|
[ancestor::CompilationUnit/ImportDeclaration/Name[starts-with(@Image,'org.springframework')]]
|
|
) | (
|
|
//Block//PrimaryExpression
|
|
[
|
|
PrimaryPrefix/Name[ends-with(@Image,'.setViewName')]
|
|
or (PrimaryPrefix/AllocationExpression/ClassOrInterfaceType[typeIs('org.springframework.web.servlet.ModelAndView')])
|
|
]
|
|
[
|
|
PrimarySuffix/Arguments/ArgumentList//PrimaryPrefix/Name[
|
|
(@Image = ancestor::MethodDeclaration//VariableDeclaratorId/@Image)
|
|
or (@Image = ancestor::ClassOrInterfaceBody//FieldDeclaration[@Final='false']//VariableDeclaratorId/@Image)]
|
|
|
|
|
PrimaryPrefix/AllocationExpression/Arguments/ArgumentList/Expression[1]/PrimaryExpression/PrimaryPrefix/Name[
|
|
(@Image = ancestor::MethodDeclaration//VariableDeclaratorId/@Image)
|
|
or (@Image = ancestor::ClassOrInterfaceBody//FieldDeclaration[@Final='false']//VariableDeclaratorId/@Image)]
|
|
|
|
|
PrimaryPrefix/AllocationExpression/Arguments/ArgumentList/Expression//Arguments//PrimaryExpression/PrimaryPrefix/Name[
|
|
(@Image = ancestor::MethodDeclaration//VariableDeclaratorId/@Image)
|
|
or (@Image = ancestor::ClassOrInterfaceBody//FieldDeclaration[@Final='false']//VariableDeclaratorId/@Image)]
|
|
]
|
|
)
|
|
]]></value>
|
|
</property>
|
|
</properties>
|
|
</rule>
|
|
|
|
<rule name="MakeAutoWiredConstructedFieldFinal"
|
|
message="Make autowired, constructed field final in objects shared among threads."
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java"
|
|
typeResolution="true" externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Performance#JavaCodePerformance-TUTC07">
|
|
<description>
|
|
Problem: Multiple threads typically access fields of a singleton or may access fields in session scoped objects. If a field or its reference is mutable, non-autowired access is thread-unsafe and may cause corruption or visibility problems. To make this thread-safe, that is, guard the field e.g. with synchronized methods, may cause contention.
|
|
Solution: Make the fields final and unmodifiable to defend against mutation. If they really need to be mutable (which is strange for autowired fields), make access thread-safe. Thread-safety can be achieved e.g. by proper synchronization and use the @GuardedBy annotation or use of volatile.
|
|
Notes
|
|
1. Autowiring/injection is thread safe, yet make sure no other thread-unsafe assignment is made to that field.
|
|
2. In case you are sure the Component is used in single threaded context only (e.g. a Tasklet), annotate the class with @NotThreadSafe to make this explicit.
|
|
3. Use package-private and @VisibleForTesting for methods (e.g. setters) used for JUnit only.
|
|
(jpinpoint-rules)</description>
|
|
<priority>4</priority>
|
|
<properties>
|
|
<property name="version" value="1.0"/>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//TypeDeclaration/Annotation//Name[(@Image='Component' or @Image='Service' or @Image='Controller' or @Image='Repository' or
|
|
(@Image='Singleton' and ancestor::TypeDeclaration/Annotation/NormalAnnotation/MemberValuePairs//Name[@Image='ConcurrencyManagementType.BEAN']))
|
|
and not (ancestor::TypeDeclaration/Annotation/NormalAnnotation/Name[@Image='Scope']/..//Literal[@Image='"request"' or @Image='"prototype"'])
|
|
and not (ancestor::TypeDeclaration/Annotation/MarkerAnnotation/Name[@Image='NotThreadSafe'])
|
|
and not ((ancestor::TypeDeclaration/Annotation/NormalAnnotation/Name[@Image='ConfigurationProperties'])
|
|
and not (ancestor::TypeDeclaration/Annotation/MarkerAnnotation/Name[@Image='Setter']))]
|
|
/../../..//ClassOrInterfaceDeclaration[@Static='false']/ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/FieldDeclaration[@Final='false' and @Volatile='false'
|
|
and not (../Annotation//Name[@Image='Autowired' or @Image='PersistenceContext' or @Image='EJB' or @Image='Resource' or @Image='Inject' or @Image='Value' or @Image='GuardedBy'])
|
|
and (../../ClassOrInterfaceBodyDeclaration/Annotation//Name[@Image='Autowired']
|
|
/../../../ConstructorDeclaration//BlockStatement/Statement//StatementExpression/AssignmentOperator/../PrimaryExpression//@Image=
|
|
./VariableDeclarator/VariableDeclaratorId/@Image)
|
|
]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
</rule>
|
|
|
|
<rule name="MinimizeActionModelMapInSession" class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java" message="ModelMap in action method is not cleared. This may bloat the session." typeResolution="true"
|
|
externalInfoUrl="http://www.jpinpoint.com/doc/Java+Code+Performance#JavaCodePerformance-TMSU12">
|
|
<description>A ModelMap is used in an action method typically for form validation and not cleared. Problem: the ModelMap is put in the session by Spring. This is typically a large object which may bloat the session.
|
|
Solution: clear the ModelMap right after the validation in the happy flow.
|
|
(jpinpoint-rules)</description>
|
|
<priority>2</priority>
|
|
<properties>
|
|
<property name="version" value="1.0"/>
|
|
<property name="xpath">
|
|
<value><![CDATA[
|
|
//ClassOrInterfaceBodyDeclaration
|
|
[MethodDeclaration[@Public='true'] and
|
|
MethodDeclaration/MethodDeclarator/FormalParameters/FormalParameter/Type/ReferenceType/ClassOrInterfaceType[typeIs('org.springframework.ui.ModelMap')] and
|
|
(MethodDeclaration/MethodDeclarator/FormalParameters/FormalParameter/Type/ReferenceType/ClassOrInterfaceType[typeIs('javax.portlet.ActionRequest')] or
|
|
Annotation//Name[@Image='ActionMapping']) and
|
|
count(.//PrimaryExpression/PrimaryPrefix/Name[ends-with(@Image,'.clear')])=0]
|
|
]]></value>
|
|
</property>
|
|
</properties>
|
|
</rule>
|
|
|
|
<!-- END Included file 'spring.xml' -->
|
|
<!-- BEGIN Included file 'sql.xml' -->
|
|
<rule name="AvoidHugeQueryFetchSize"
|
|
message="Avoid a huge query fetch size, it consumes much memory."
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java"
|
|
typeResolution="true" externalInfoUrl="http://www.jpinpoint.com/doc/Java+Data+Access+Performance#JavaDataAccessPerformance-IDA-TRM03">
|
|
<description>
|
|
Problem: if huge numbers of result rows are fetched these are all stored in memory and this may introduce long gc times and out of memory risk.
|
|
Solution: Set fetch size to 100 maximally. Only set it higher than 100 yet still max 500, if you are sure there is only little data returned per row, like 3 rather short columns.
|
|
(jpinpoint-rules)</description>
|
|
<properties>
|
|
<property name="version" value="1.0"/>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//MethodDeclaration//PrimaryExpression[PrimaryPrefix/Name[ends-with(@Image, '.setFetchSize')]
|
|
[ancestor::PrimaryExpression/PrimarySuffix/Arguments/ArgumentList/Expression/PrimaryExpression/PrimaryPrefix/Literal[@Image > 500]]]
|
|
|
|
|
//MethodDeclaration//PrimaryExpression[PrimaryPrefix/Name[ends-with(@Image, '.setFetchSize')]
|
|
[ancestor::PrimaryExpression/PrimarySuffix/Arguments/ArgumentList/Expression/PrimaryExpression/PrimaryPrefix/Name[@Image =
|
|
ancestor::ClassOrInterfaceBody//VariableDeclarator/VariableDeclaratorId/@Image
|
|
[ancestor::VariableDeclarator/VariableInitializer/Expression/PrimaryExpression/PrimaryPrefix/Literal[@Image > 500]]]]]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<priority>2</priority>
|
|
</rule>
|
|
|
|
<rule name="AvoidMultipleRoundtripsForQuery"
|
|
message="Avoid multiple roundtrips for the same query"
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java"
|
|
typeResolution="true" externalInfoUrl="http://www.jpinpoint.com/doc/Java+Data+Access+Performance#JavaDataAccessPerformance-IDA-TRR05">
|
|
<description>
|
|
Problem: Time is taken by the unnecessary roundtrip(s). Unnecessary work is performed.
|
|
Solution: Execute the query only once.
|
|
(jpinpoint-rules)</description>
|
|
<properties>
|
|
<property name="version" value="2.0"/>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//MethodDeclaration/Block//PrimaryExpression/PrimaryPrefix/Name[ends-with(@Image, '.getSingleResult')]
|
|
[ancestor::MethodDeclaration[count(.//VariableInitializer/Expression/PrimaryExpression/PrimarySuffix[@Image='createQuery']) = 1
|
|
and
|
|
count(.//PrimaryExpression/PrimaryPrefix/Name[ends-with(@Image, '.getResultList')]) +
|
|
count(.//PrimaryExpression/PrimaryPrefix/Name[ends-with(@Image, '.getSingleResult')])
|
|
> 1]]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<priority>2</priority>
|
|
</rule>
|
|
|
|
<rule name="AvoidSqlInExpression"
|
|
message="Avoid a SQL IN-Expression, it fails for > 1000 arguments and pollutes the query plan cache / statement cache"
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule" deprecated="false" dfa="false" language="java"
|
|
typeResolution="true" externalInfoUrl="http://www.jpinpoint.com/doc/Java+Data+Access+Performance#JavaDataAccessPerformance-IDA-INO01">
|
|
<description>
|
|
Problem: The number of values for the IN-argument list is limited, in Oracle to 1000. An error occurs when exceeding this limit. Additionally, a large IN list takes much time to transport to the database and be parsed. Moreover, each number of IN values used in a query results in a separate cache entry in e.g. the Prepared Statement Cache of the application server and in the Hibernate Query Plan Cache, resulting in higher memory usage and/or low cache hit ratio.
|
|
Solution: Rewrite the query by replacing the IN-argument list by a sub query using the criteria used to fetch the IN arguments. Or often even better performing, an inner join using these criteria (depending on indexes etc. - recommended to test to be sure.) This way, the select and update are combined into one, which will also save one roundtrip.
|
|
(jpinpoint-rules)</description>
|
|
<properties>
|
|
<property name="version" value="2.0"/>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
|
|
//ClassOrInterfaceDeclaration/ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/MethodDeclaration/Block
|
|
//Expression/PrimaryExpression/PrimaryPrefix/Name[@Image='InExpression.in']
|
|
|
|
|
//TypeDeclaration/Annotation/SingleMemberAnnotation/Name[@Image='NamedQueries']
|
|
/../MemberValue//PrimaryExpression/PrimaryPrefix/Literal[contains(@Image, 'WHERE') and
|
|
(contains(@Image, ' IN(:') or contains(@Image, ' IN (:') or contains(@Image, ' IN :') or contains(@Image, ' IN ( :')) ]
|
|
|
|
|
//LocalVariableDeclaration/VariableDeclarator/VariableInitializer//PrimaryPrefix[Literal[contains(@Image, ' IN') and contains(@Image, ':')]
|
|
and starts-with(Literal[(contains(@Image, ' IN') and contains(@Image, ':'))]/
|
|
substring-after(substring-after(@Image, ' IN'), ':')
|
|
,
|
|
ancestor::MethodDeclaration//BlockStatement//PrimaryPrefix/Name[ends-with(@Image, '.setParameter')]
|
|
/../../PrimarySuffix/Arguments/ArgumentList[Expression/PrimaryExpression/PrimaryPrefix/Name[@Image != 'Arrays.asList']]/Expression/PrimaryExpression/PrimaryPrefix/Literal/substring-before(substring-after(@Image, '"'),'"'))
|
|
and
|
|
ancestor::MethodDeclaration//BlockStatement//PrimaryPrefix/Name[ends-with(@Image, '.setParameter')]
|
|
/../../PrimarySuffix/Arguments/ArgumentList/Expression/PrimaryExpression/PrimaryPrefix/Name[@Image != 'Arrays.asList']
|
|
]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<priority>2</priority>
|
|
</rule>
|
|
|
|
<!-- END Included file 'sql.xml' -->
|
|
</ruleset> |