diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000..6c079421db --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,211 @@ +# Contributing + +This repository contains **PMD jPinpoint rules, unit tests and documentation** (Java + Kotlin). + +## General guidelines + +A couple of general guidelines that help the review process: + +- Create an issue with a clear problem description and add test cases and a solution approach when possible. +- Align on the applicability, scope and approach before opening a pull request. +- Please avoid reformatting unrelated code; keep changes limited to the area you’re fixing so the diff stays focused and easier to review. +- When changing a rule, please add (or update) unit tests that cover the new behavior. + +## How to contribute + +1. **Open an issue first** + - Bug report: include version, rule name, minimal reproduction code, and expected vs actual behavior. + - Rule enhancement / new rule: include examples for **violations** and **no violations**. + - Please use standard issue title prefixes and include the language: + - `Fix Request (Java): ...` / `Fix Request (Kotlin): ...` + - `Rule Request (Java): ...` / `Rule Request (Kotlin): ...` +2. **Create a branch** from `pmd7` (!) and keep the change focused. +3. **Update/add unit tests** for the behavior you changed. +4. **Run tests locally** (`./mvnw clean test`) and ensure they pass. +5. **Open a pull request** + - Link the issue. + - Describe what changed and why. + - Include notes about any false-positive / false-negative tradeoffs if relevant. + +## Development + +To start development on the ruleset the PMD tool designer may come in handy. +Download it from the [PMD project at github](https://pmd.github.io/) and install it using the instructions on their site. + +After installation and configuration you can start the designer from the command prompt: + +```bash +pmd.bat designer +``` + +or + +```bash +./pmd designer +``` + +## Build and run tests + +The project is built using **Maven**. The build runs the **unit tests** which validate the rules. + +From the repository root: + +```bash +./test +``` + +## Adding new rules + +You can add new rules using the steps below. + +The steps basically tell you to create an issue, add documentation and create 3 files. +As an example you can copy existing files and change the content according to your needs. +Always work along the lines of what already exists. + +For Kotlin: use the paths that contain `/kotlin/` instead of `/java/`. + +- Create an issue like **"Rule Request: AvoidRecreatingExpensiveThing"** with simple compiling examples which can be used as tests. + Use this issue reference with check-in. +- Document the pitfall in the proper page and category in `docs/` and + [regenerate the ToC](https://luciopaiva.com/markdown-toc/). +- Add the test class in + `src/test/java/com/.../perf/lang/java/ruleset/yourruleset/YourRule.java`. + Elements from the package structure are used to lookup the rules XML file you add next. + The relevant items based on the example given are: `lang/java/ruleset/yourruleset`. +- Rules go into XML files found in `src/main/resources/category/`. + In this case: `src/main/resources/category/java/yourruleset.xml`. + Also add a rule with name `YourRule` since that is what the framework expects. + For new rule files (a new category) you will also need to register it in the + `categories.properties` file found in the same directory + (`category/java/categories.properties`), in this case add `category/java/yourruleset.xml`. +- Add the unit test in an XML file in + `src/test/resources/com/.../perf/lang/java/ruleset/yourruleset/xml/YourRule.xml`. + Pay attention to the package structure which is also dictated by the first Java test class. + +Depending on what you want to add you may find it is sufficient to change one or more existing files. +Or to add only a test class and unit test XML file. + +### Conventions for XML unit test files + +Following are some conventions and recommendations on how to construct the unit test files: + +- Separate test code (create separate `` blocks) +- Specify test code description (``). Start the description with: + - **violation:** or + - **no violation:** +- Specify number of occurrences (``) +- Specify line-numbers (``) +- Code conventions (``): + - use class names like `Foo` + - use method names like `bad` and `good` + - add comment at the end of bad lines `//bad` + - remove useless code and `import` statements + +## Run Kotlin unit tests + +When running unit tests for Kotlin, PMD 7 is needed. +Make sure you have access to the PMD jars of the `7.2.24-SNAPSHOT` branch (e.g. `./mvnw install` the PMD 7.2.x jars from https://github.com/pmd/pmd). +Use the Maven `kotlin-pmd7` profile when running the Kotlin unit tests. + +> Note: use `./mvnw` (the Maven Wrapper) for all builds in this repository. + +## Code style indentation + +- Indentation: use spaces (disable tabs): + *Settings → Editor → Code Style → Java → Use tab character (disable)* + +## Contents of the project + +- `rulesets/java/jpinpoint-rules.xml` contains the PMD custom rule definitions. +- `src/main/java/pinpointrules` contains the Java code containing pitfalls for testing the rules. +- `rulesets-merger` contains the Java code for a ruleset merger tool. + +## Merging rules + +The merger tool can merge rule categories into a single ruleset file used by IDE plugins. + +Build the merger tool: + +```bash +cd rulesets-merger +./mvnw clean install +``` + +Run the merger tool: + +```bash +cd rulesets-merger +./mvnw exec:java -Dexec.args="java" +``` + +or simply: + +```bash +./merge +``` + +For Kotlin instead of Java: + +```bash +./merge kotlin +``` + +### Merging with company-specific rules + +Company-specific rules are useful for instance for checking the right use of company-specific or company-bought frameworks and libraries. + +Copy `rulesets-merger` to your company rules directory and adjust a few constants at the top to make it work for your company. + +The merge tool runs for either Java or Kotlin rules. Use the first argument to choose: `java` or `kotlin`. + +After building, the merger tool can be run with: + +```bash +cd rulesets-merger +./mvnw exec:java -Dexec.args="java" +``` + +or simply: + +```bash +./merge +``` + +For Kotlin instead of Java: + +```bash +./merge kotlin +``` + +It will attempt to locate the `PMD-jPinpoint-rules` project next to your own project and merge +`rulesets/[java|kotlin]/jpinpoint-rules.xml` together with your rule files (from `src/main/resources/category/[java|kotlin]/*.xml`). + +It assumes you have repositories in directories next to each other: + +```text +PMD-Company-jPinpoint-rules +PMD-jPinpoint-rules (optional) +``` + +It will generate: + +```text +company-rules.xml +company-jpinpoint-rules.xml +``` + +You can also specify the external repo explicitly, e.g.: + +```bash +cd target +java -jar rulesets-merger-1.0-SNAPSHOT.jar PMD-jPinpoint-rules rulesets/java jpinpoint-rules.xml +``` + +For Kotlin: + +```bash +cd target +java -jar rulesets-merger-1.0-SNAPSHOT.jar PMD-jPinpoint-rules rulesets/kotlin jpinpoint-rules.xml +``` + + diff --git a/README.md b/README.md index 36482582ce..c4e2a5eefd 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,31 @@ Static code checking rules for responsible Java and Kotlin programming built on These rules are on performance, sustainability, multi-threading, data mix-up, and more. +## Quickstart + +The quickest way to see these rules in action is to install the IntelliJ PMD plugin: + + Settings > Plugins > Browse Repositories > Search 'PMD' > Select 'PMD' > Install > Close > OK > Restart + +Next, add the Java and/or Kotlin rule sets: + + Settings > Tools > PMD > RuleSets > + > Choose RuleSet > drop down > Choose 'jpinpoint-kotlin-rules' or 'jpinpoint-java-rules' > OK > OK + +IntelliJ PMD dropdown + +Then right-click on a source folder or file and choose: + + Run PMD > Custom rules > jpinpoint-java-rules or jpinpoint-kotlin-rules + +IntelliJ PMD run + +The result is a list of violations of the rules, with a description and a link to documentation on the rule, the problem and the solution. + +IntelliJ PMD results + ## Purpose -The purpose of this project is to create, manage and share these rules, to code better software together: + +The aim of this project is to create, manage and share these rules, to code better software together: better software which is faster, uses less resources, has a smaller ecological footprint, is more stable, more confidential, with less effort and lower cost. More general, to promote responsibility by considering the concerns of the user, the environment, the engineer, the community and the company. @@ -13,43 +36,40 @@ We have distilled these code checks from what we learned in several years of ana We didn't find these checks in other places, like the standard PMD, FindBugs/Spotbugs, Checkstyle or Sonar rules. We are working with the PMD-team to move some of the jpinpoint rules in the standard rule set, as well as make PMD suitable for Kotlin. -## How to use the rules +## Documentation -Run the jPinpoint rules from the command-line using the PMD tool, from your favorite development -environment with a PMD-plugin, or in SonarQube with the [sonar-pmd-jpinpoint plugin](https://github.com/jborgers/sonar-pmd-jpinpoint) -next to the [Sonar pmd plugin](https://github.com/jborgers/sonar-pmd). - -Documentation of the rules are here: * [JavaCodePerformance](docs/JavaCodePerformance.md) * [JavaDataAccessPerformance](docs/JavaDataAccessPerformance.md) * [JavaCodeQuality](docs/JavaCodeQuality.md) -## License -PMD-jPinpoint-rules is licensed under the [Apache License, Version 2.0](https://github.com/jborgers/pmd-jpinpoint-rules/blob/master/LICENSE.md). +## Presentations and articles -## See also - How Bol uses the jPinpoint rules: [How to prevent common performance defects with the jPinpoint PMD rules](https://techlab.bol.com/en/blog/how-to-prevent-common-performance-defects-with-the-jpinpoint-pmd-rules/) - Jeroen Borgers presented at J-Fall Virtual: [Fixing your performance and concurrency bugs before they bite you](https://youtu.be/Z_sT38KTRNk) - Jeroen Borgers presented at Amsterdam JUG about the why, what and how of these code checking rules: [Performance problem prevention](https://www.meetup.com/nl-NL/Amsterdam-Java-User-Group/events/256497068/) | [slides](http://jpinpoint.com/resources/Automated-and-learning-performance-problem-prevention-AMS-JUG.pdf) -# Usage +## Ways to use the rules + +Run the jPinpoint rules from the command-line using the PMD tool, from your favorite development +environment with a PMD-plugin, or in SonarQube with the [sonar-pmd-jpinpoint plugin](https://github.com/jborgers/sonar-pmd-jpinpoint) +next to the [Sonar pmd plugin](https://github.com/jborgers/sonar-pmd). To use the ruleset you can install: - the PMD command line tool from [PMD project at github](https://pmd.github.io/) and/or - the PMD-Plugin in your development environment. -## PMD command line tool +### PMD command line tool -After installing the tool you can run `pmd.sh` or `pmd.bat` similar to the following +After installing the PMD tool you can run `pmd` similar to the following - pmd.sh \ + pmd check \ -R PMD-jPinpoint-rules/rulesets/java/jpinpoint-rules.xml \ -d $your-project-src \ -f text -## IntelliJ IDEA with PMD Plugin +### IntelliJ IDEA with PMD Plugin - You need version 2024-1+ of IntelliJ. The Community Edition is fine. - Install PMD Plugin: @@ -73,179 +93,21 @@ After installing the tool you can run `pmd.sh` or `pmd.bat` similar to the follo - Documentation on a violation is shown on the right hand side after clicking a violation. More details of the problem and solution are shown with right-clicking 'Details'. -## Eclipse with PMD Plugin +### Eclipse with PMD Plugin The Acanda PMD plugin seems to be the best one to use. - [Import it into eclipse](http://www.acanda.ch/eclipse-pmd/release/latest). - enable PMD through the properties of the project - add the ruleset from this project *[rulesets/java/jpinpoint-rules.xml](https://raw.githubusercontent.com/jborgers/PMD-jPinpoint-rules/refs/heads/pmd7/rulesets/java/jpinpoint-rules.xml)* -## SonarQube with Plugins -In SonarQube, you need to install [sonar-pmd plugin](https://github.com/jborgers/sonar-pmd) from the marketplace, and [sonar-pmd-jpinpoint plugin](https://github.com/jborgers/sonar-pmd-jpinpoint) for these jpinpoint rules. - -# Development - -To start development on the ruleset the PDM tool designer may come in handy. -Download it from the [PMD project at github](https://pmd.github.io/) and install it using the instructions on their site. - -After installation and configuration you can start the designer from the command prompt: - - designer.bat - -or - - ./pmd designer - -## Rules and unit tests - -The project can be build using **maven**. The build will perform the **unit tests** which will unit-test -the rules. The next paragraph "Adding new rules" will describe in more detail where you can find the rule files. -To run the unit tests run the following command from the project home directory of: - - mvn clean test - -or simply: - - ./test - -## Adding new rules - -You can add new rules using the steps below. - -The steps basically tell you to create an issue, add documentation and create 3 files. -As an example you can copy existing files and change the content according to your needs. Always work along the lines of what already exists. - -For Kotlin: use the paths that contain `/kotlin/` instead of `/java/`. - -- create an issue like 'Rule Request: AvoidRecreatingExpensiveThing' with simple compiling examples which can be used as tests. Use this issue reference with check-in. -- document the pitfall in the proper page and category in docs/ and [regenerate the ToC](https://luciopaiva.com/markdown-toc/) -- add the Test class in `src/test/java/com/.../perf/lang/java/ruleset/yourruleset/YourRule.java` -elements from the package structure are used to lookup the rules xml file you add next. -The relevant items based on the example given are: lang/**java**/ruleset/**yourruleset** -- rules go into xml files found in `src/main/resources/category/` in this case -src/main/resources/category/**java**/**yourruleset.xml**. Also add a rule with name `YourRule` -since that is what the framework expects. -For new rule files (a new category) you will also need to register it in the `categories.properties` file found in the same directory -(category/java/categories.properties) in this case add `category/java/yourruleset.xml` -- add the unit test in an xml file in -`src/test/resources/com/.../perf/lang/java/ruleset/yourruleset/xml/YourRule.xml`. -Pay attention to the package structure which is also dictated by the first java test class! - -Depending on what you want to add you may also find it is sufficient to change one or more of the existing files. -Or to add only a Test class and unit test xml file (steps 1 and 3). +### SonarQube with Plugins -### Conventions for XML Unit test files - -Following are some conventions and recommendations on how to -construct the unit test files: - -- separate test code *(create separate ```` blocks)* -- specify test code description *(````)* Start the description with: - - **violation:** or - - **no violation:** -- specify number of occurrences *(````)* -- specify line-numbers *(````)* -- code *(````)* conventions: - - use class names like **``Foo``** - - use method names like **``bad``** and **``good``** - - add comment at the end of bad lines **``//bad``** - - remove useless code and **``import``** statements - -### Run Kotlin Unit Tests - -When running unit tests for Kotlin PMD 7 is needed. Make sure you have access to the PMD jars of the `7.0.0-SNAPSHOT` -branch (e.g. mvn install the PMD 7.0.x jars from https://github.com/pmd/pmd). Use the Maven `kotlin-pmd7` profile -when running the Kotlin unit tests. - -## Code Style Indentation - -- Indentation: Use spaces a.k.a. **Disable Tabs**: *Settings>Editor>Code Style>Java>Use tab character [disable]* - -## Contents of the project -- `rulesets/java/jpinpoint-rules.xml` contains the pmd custom rule definitions -- `src/main/java/pinpointrules` contains the Java code containing pitfalls for testing the rules. -- `rulesets-merger` contains the Java code for a ruleset merger tool. - -## Merging rules - -- `rulesets-merger/src` contains RulesetMerger.java for merging jpinpoint-rules. - - The merger tool can be built with: - - cd rulesets-merger - mvn clean install - -### Merging from different categories - - Run the merger tool as follows: - - cd rulesets-merger - mvn exec:java -Dexec.args="java" - - or simply: - - ./merge - -or for Kotlin instead of Java: - - ./merge kotlin - - It will merge the rules from ``src/main/resources/category/java/*.xml`` to create the jpinpoint-rules.xml file which can be used in your IDE. - -### Merging with company specific rules - -Company specific rules are useful for instance for checking the right use of company specific or company-bought frameworks and libraries. -Or for rules which are candidates for inclusion into jpinpoint rules, yet need to be validated first. - -- `rulesets-merger/src` contains RulesetMerger.java for merging jpinpoint-rules with company specific rules. -Copy rulesets-merger to your company specific rules directory and adjust a few constants at the top to make it work for your company. - -The merge tool runs either for the java or the kotlin rules. Use the first argument to choose: java or kotlin. - - After building, the merger tool can be run with: - - cd rulesets-merger - mvn exec:java -Dexec.args="java" - -or simply - - ./merge - -or for Kotlin instead of Java: - - ./merge kotlin +In SonarQube, you need to install [sonar-pmd plugin](https://github.com/jborgers/sonar-pmd) from the marketplace, and [sonar-pmd-jpinpoint plugin](https://github.com/jborgers/sonar-pmd-jpinpoint) for these jpinpoint rules. - This will attempt to lookup the PMD-jPinpoint-rules project (next to your own project) - and merge `rulesets/[java|kotlin]/jpinpoint-rules.xml` together with your rule files (from `src/main/resources/category/[java|kotlin]/*.xml`) - The resulting file can be used in your IDE. - - It assumes you have the following repositories in directories next to each other: - - PMD-Company-jPinpoint-rules - PMD-jPinpoint-rules (optional) - - It can be built and run the same way. - - It will generate two files: - - company-rules.xml - company-jpinpoint-rules.xml - - These files can be used in your IDE. The former only contains the company specific rules. - The latter contains all rules combined and will only be generated if the optional PMD-jPinpoint-rules repo is available. - - You can also do it yourself and specify the external repo to merge with explicitly: - - cd target - java -jar java rulesets-merger-1.0-SNAPSHOT.jar PMD-jPinpoint-rules rulesets/java jpinpoint-rules.xml +## Development and contribution -or for Kotlin: +Development docs (building, tests, adding rules, merging rules) are in [`CONTRIBUTING.md`](CONTRIBUTING.md) - cd target - java -jar kotlin rulesets-merger-1.0-SNAPSHOT.jar PMD-jPinpoint-rules rulesets/kotlin jpinpoint-rules.xml +## License -## Tools to create documentation -1. Confluence export as HTML -2. [Converting HTML to Markdown](https://domchristie.github.io/turndown/) -3. [Markdown TOC generator](https://luciopaiva.com/markdown-toc/ -) +PMD-jPinpoint-rules is licensed under the [Apache License, Version 2.0](https://github.com/jborgers/pmd-jpinpoint-rules/blob/master/LICENSE.md). diff --git a/docs/JavaCodePerformance.md b/docs/JavaCodePerformance.md index 7e8080d490..20cb655f3a 100644 --- a/docs/JavaCodePerformance.md +++ b/docs/JavaCodePerformance.md @@ -1704,7 +1704,7 @@ Loading the classes every time means excessive class loading, it results in poor **Note:** The implementation class of the factory actually used might be just the default class specified in the factory interface code. The service loading mechanism will use this class when no other implementor is found in your classpath. Find out from a heap dump or classloading logging (-verbose:class) which one is actually used in your app. Here it shows in a heap dump in VisualVM as only class with objects retaining bytes: -![transformerFactory in heap](transformerFactoryInHeap.png) +![transformerFactory in heap](images/transformerFactoryInHeap.png) **Note:** More on `TransformerFactory` and caching compiled templates, see IBM's [XSLT transformations cause high CPU and slow performance](http://www-01.ibm.com/support/docview.wss?uid=swg21641274). diff --git a/docs/images/intellij-pmd-dropdown-light.png b/docs/images/intellij-pmd-dropdown-light.png new file mode 100644 index 0000000000..1b056c353a Binary files /dev/null and b/docs/images/intellij-pmd-dropdown-light.png differ diff --git a/docs/images/intellij-pmd-results-light.png b/docs/images/intellij-pmd-results-light.png new file mode 100644 index 0000000000..c30fc26f2a Binary files /dev/null and b/docs/images/intellij-pmd-results-light.png differ diff --git a/docs/images/intellij-pmd-run-light.png b/docs/images/intellij-pmd-run-light.png new file mode 100644 index 0000000000..25421fd0ab Binary files /dev/null and b/docs/images/intellij-pmd-run-light.png differ diff --git a/docs/transformerFactoryInHeap.png b/docs/images/transformerFactoryInHeap.png similarity index 100% rename from docs/transformerFactoryInHeap.png rename to docs/images/transformerFactoryInHeap.png