Skip to content

Commit

Permalink
Merge pull request #294 from jborgers/kotlin/AvoidSimpleDateFormat
Browse files Browse the repository at this point in the history
added AvoidSimpleDataFormat for Kotlin
  • Loading branch information
jborgers committed Mar 11, 2024
2 parents 67c03ad + 46b36dc commit fbb0652
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 0 deletions.
43 changes: 43 additions & 0 deletions src/main/resources/category/kotlin/common.xml
Expand Up @@ -133,4 +133,47 @@ class Foo {
</example>
</rule>

<rule name="AvoidSimpleDateFormat"
class="net.sourceforge.pmd.lang.rule.XPathRule"
dfa="false"
language="kotlin"
message="SimpleDateFormat is used. Since it is thread-unsafe, it needs expensive recreation."
typeResolution="true"
externalInfoUrl="${doc_root}/JavaCodePerformance.md#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. &#13;
Solution: Use java.time.DateTimeFormatter. These classes are immutable, thus thread-safe and can be made static.
(jpinpoint-rules)</description>
<priority>2</priority>
<properties>
<property name="tag" value="jpinpoint-rule" type="String" description="for-sonar"/>
<property name="version" value="3.1"/>
<property name="xpath">
<value><![CDATA[
(: check if java.text imports exists as filter for same named classes in other packages :)
//ImportHeader[.//T-Identifier[@Text='java'] and .//T-Identifier[@Text='text']][1]/../..
(: if used in setDateFormat function, allow if jackson ObjectMapper or XmlMapper is used :)
//ClassMemberDeclaration//SimpleIdentifier//T-Identifier[(@Text="SimpleDateFormat")
and not (ancestor::ClassMemberDeclaration//T-Identifier[@Text="setDateFormat"]
and //ImportHeader[.//T-Identifier[@Text='fasterxml'] and .//T-Identifier[@Text='jackson']]
)
]
]]></value>
</property>
</properties>
<example><![CDATA[
import java.text.SimpleDateFormat
import java.util.*
class Foo {
private fun toKey(calcDate: Date): String {
val formatter = SimpleDateFormat("yyyy-MM-dd") //bad
return formatter.format(calcDate)
}
}
]]>
</example>
</rule>


</ruleset>
@@ -0,0 +1,6 @@
package com.jpinpoint.perf.lang.kotlin.ruleset.common;

import net.sourceforge.pmd.testframework.PmdRuleTst;

public class AvoidSimpleDateFormatTest extends PmdRuleTst {
}
@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8"?>
<test-data
xmlns="http://pmd.sourceforge.net/rule-tests"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sourceforge.net/rule-tests http://pmd.sourceforge.net/rule-tests_1_0_0.xsd">
<test-code>
<description>violation: Avoid the use of SimpleDateFormat</description>
<expected-problems>1</expected-problems>
<expected-linenumbers>6</expected-linenumbers>
<code><![CDATA[
import java.text.SimpleDateFormat
import java.util.*
class Foo {
private fun toKey(rekenDatum: Date): String {
val formatter = SimpleDateFormat("yyyy-MM-dd") //bad
return formatter.format(rekenDatum)
}
}
]]></code>
</test-code>
<test-code>
<description>no violation: SimpleDateFormat is allowed in Jackon's ObjectMapper</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.dataformat.xml.XmlMapper
import java.text.SimpleDateFormat
object Foo {
private val OBJECT_MAPPER = createObjectMapper()
private val XML_MAPPER: XmlMapper
private val unknown: Unknown = createUnknownObject()
init {
XML_MAPPER = XmlMapper()
val df = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss") // good, used in XmlMapper
XML_MAPPER.setDateFormat(df)
}
private fun createObjectMapper(): ObjectMapper {
val mapper = ObjectMapper()
mapper.setDateFormat(SimpleDateFormat("yyyy-MM-dd")) // good, used in ObjectMapper
return mapper
}
}
]]></code>
</test-code>
<test-code>
<description>violation: SimpleDateFormat is not allowed in non XmlMapper or ObjectMapper</description>
<expected-problems>1</expected-problems>
<expected-linenumbers>8</expected-linenumbers>
<code><![CDATA[
import java.text.SimpleDateFormat
object Foo {
private val unknown: Unknown = createUnknownObject()
private fun createUnknownObject(): Unknown {
val unknown: Unknown = Unknown()
unknown.setDateFormat(SimpleDateFormat("yyyy-MM-dd")) // bad, used in unknown object
return unknown
}
}
]]></code>
</test-code>
</test-data>

0 comments on commit fbb0652

Please sign in to comment.