[JAVA] Use static analysis tools in your Gradle project

Overview

Gradle comes standard with plugins for using static analysis tools. Learn how to bring them into your Gradle project.

If you find something wrong, please let us know or request an edit. : bow:

Article background

"Software testing from zero knowledge [revised edition]" When I was reading the book, I suddenly found that my project was Cyclomatic Complexity. I want to measure complexity).

: question: Why Gradle

In Java, there is a plug-in in Eclipse, but I personally want to use Eclipse only for writing code, and I also think that the Gradle plug-in makes it easy to reproduce the environment, so Gradle I wondered if it could be used from, and found out that the PMD plug-in is provided as standard. There are quite a lot of commentary articles in Japanese for this plug-in, and if I proceeded with reference to it, I was able to measure without any problems.

: do_not_litter: If you have another existing article, you can just include the link and you don't have to bother writing the article.

This time, I will introduce how to use it easily, including plugins that use other static analysis tools.

What is static analysis?

It is said that the method of analyzing without executing the program is called so. In Java, let the tool parse the source code and bytecode. Automatically executed by the machine can help you find bugs and inconsistencies that are difficult for the human eye to find, prevent bugs that may be embedded in the future, or rewrite them into more readable code.

Execution environment

Product Version
Java SE 1.8.0_111
OS Windows 10
Gradle 3.2.1

Target project

Use the previously created RatPack sample code.

Folder hierarchy(tree /f)


src
├─main
│  ├─java
│  │  └─jp
│  │      └─toastkid
│  │          ├─libs
│  │          │  └─tinysegmenter
│  │          │          CharacterClassifier.java
│  │          │          ScoreMap.java
│  │          │          TinySegmenter.java
│  │          │
│  │          └─ratpack
│  │              │  Main.java
│  │              │
│  │              └─models
│  │                      WordCloud.java
│  │
│  └─resources
│      │  .ratpack
│      │  wordcloud.html
│      │
│      └─public
│          ├─images
│          │      favicon.png
│          │      icon.png
│          │
│          ├─javascripts
│          │  │  jquery-1.6.4.min.js
│          │  │
│          │  ├─d3
│          │  │      d3.js
│          │  │      LICENSE(d3)
│          │  │
│          │  └─d3-cloud
│          │          d3.layout.cloud.js
│          │          index.js
│          │          LICENSE
│          │          package.json
│          │          README.md
│          │
│          └─stylesheets
│                  main.css
│
└─test
    └─java
        └─jp
            └─toastkid
                └─ratpack
                    └─models
                            WordCloudTest.java

PMD It is a static analysis tool that points out problematic code from basic programming indicators.

Introduction

You can use it just by specifying the addition of the plugin.

build.gradle


apply plugin: 'pmd'

Run

$ gradle pmdmainPlease run the.

Run


$ gradle pmdMain

:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:pmdMain

BUILD SUCCESSFUL

Total time: 2.938 secs

The report file is output to `` `build / reports / pmd``` in HTML and XML format.

pmd1.png

rule added

Basic, which is used by default, has few check items, so let's add a little. In PMD, you can use the rules posted at the link below.

http://pmd.sourceforge.net/pmd-4.3.0/rules/index.html

Cyclomatic Complexity can be measured by CodeSize. Now let's add Braces and CodeSize. Note that the prefix `` `java-``` was required when specifying the rule.

build.gradle


pmd {
  ruleSets = [
    'java-braces',
    'java-codesize',
  ]
}

Run

$ gradle pmdmainPlease run the.

Run


$ gradle pmdMain

:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:pmdMain FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':pmdMain'.
> 10 PMD rule violations were found. See the report at: file:///C:/Users/Toast%20kid/Documents/workspace/ratpack_word_cloud-master/build/reports/pmd/main.html

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

Total time: 2.266 secs

The build failed forcibly because the number of indications was above a certain level.

Points to be pointed out

pmd2.png

project\src\main\java\jp\toastkid\libs\tinysegmenter\ScoreMap.java 	1492 	The constructor 'ScoreMap' has a Cyclomatic Complexity of 43.

It was pointed out that "ScoreMap.java constructor has 43 Cyclomatic Complexity". The lower this value is, the more concise the code is, with more than 20 being cautionary and more than 50 being quite complex. By default, CodeSize gives a Warning when it is 10 or more.

Cyclomatic Complexity formula

C = number of program routes-number of program branch points + 2

: warning: Don't treat build as a failure even if there are too many indications

That's not always a good thing, but in that case you can add ignoreFailures = true and the build will succeed.

Added to build.gradle

build.gradle


pmd {
  ignoreFailures = true
  ruleSets = [
……
}

Run

$ gradle pmdmainPlease run the.

Run


$ gradle pmdMain

:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:pmdMain
10 PMD rule violations were found. See the report at: file:///C:/Users/Toast%20kid/Documents/workspace/ratpack_word_cloud-master/build/reports/pmd/main.html

BUILD SUCCESSFUL

Total time: 2.25 secs

reference

-Perform static analysis with PMD in Gradle -Chapter 33 PMD Plugin


FindBugs It is a static analysis tool that points out the parts that are likely to be a hotbed of bugs from Java code.

Introduction

Add to build.gradle.

build.gradle


apply plugin: 'findbugs'

Run

$ gradle findbugsmainExecute the analysis with the command.

Run


$ gradle findbugsMain

:compileJava
:processResources
:classes
:findbugsMain
Download https://repo1.maven.org/maven2/com/google/code/findbugs/findbugs/3.0.1/findbugs-3.0.1.pom

...(Omission)...

Download https://repo1.maven.org/maven2/org/ow2/asm/asm/5.0.2/asm-5.0.2.jar

:findbugsMain
FindBugs rule violations were found. See the report at: projet/build/reports/findbugs/main.xml

Report

The analysis result is output in XML. I want to see it in HTML, but I couldn't find the option.

Sample


  <BugInstance type="NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE" priority="2" rank="13" abbrev="NP" category="STYLE">
    <Class classname="jp.toastkid.jfx.common.Style">
      <SourceLine classname="jp.toastkid.jfx.common.Style" start="36" end="137" sourcefile="Style.java" sourcepath="jp/toastkid/jfx/common/Style.java"/>
    </Class>
    <Method classname="jp.toastkid.jfx.common.Style" name="findJarResourceDir" signature="()Ljava/util/List;" isStatic="true">
      <SourceLine classname="jp.toastkid.jfx.common.Style" start="117" end="137" startBytecode="0" endBytecode="633" sourcefile="Style.java" sourcepath="jp/toastkid/jfx/common/Style.java"/>
    </Method>
    <LocalVariable name="?" register="-1" pc="219" role="LOCAL_VARIABLE_UNKNOWN"/>
    <SourceLine classname="jp.toastkid.jfx.common.Style" start="133" end="133" startBytecode="219" endBytecode="219" sourcefile="Style.java" sourcepath="jp/toastkid/jfx/common/Style.java" role="SOURCE_LINE_INVOKED"/>
    <SourceLine classname="jp.toastkid.jfx.common.Style" start="133" end="133" startBytecode="216" endBytecode="216" sourcefile="Style.java" sourcepath="jp/toastkid/jfx/common/Style.java" role="SOURCE_LINE_KNOWN_NULL"/>
    <Property name="edu.umd.cs.findbugs.detect.NullDerefProperty.DEREFS_ARE_CLONED" value="true"/>
  </BugInstance>

: warning: Don't treat build as a failure even if there are too many indications

If you add ignoreFailures = true to this plugin as well, the build will not be treated as a failure no matter how many warnings are issued.

build.gradle


findbugs {
  ignoreFailures = true

reference

-Chapter 31 FindBugs Plugin


Checkstyle Checkstyle is a tool for checking that Java source code complies with coding standards.

Introduction

Add the following line to build.gradle.

build.gradle


apply plugin: 'checkstyle'

: no_entry: Execute (failure)

$ gradle checkRun the check with. If you want to check this plugin alone$ gradle checkstylemainIt is possible with.

Run(Failure)


$ gradle check

:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:checkstyleMain
Download https://repo1.maven.org/maven2/com/puppycrawl/tools/checkstyle/5.9/checkstyle-5.9.pom

……(Omission)……

Download https://repo1.maven.org/maven2/com/google/guava/guava-jdk5/14.0.1/guava-jdk5-14.0.1.jar
:checkstyleMain FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':checkstyleMain'.
> Unable to create a Checker: unable to find project\config\checkstyle\checkstyle.xml

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

Total time: 7.326 secs

Add configuration file

If you run the check with nothing, it will fail as above. You need to prepare a checkstyle configuration file. So, get the configuration file that reproduces Sun's conventions from the following.

https://github.com/checkstyle/checkstyle

Add the config / checkstyle folder to the root of your project and put the checkstyle.xml there.

: no_entry: Execute again (failure)

The command is the same as before.

Run


$ gradle check

:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:checkstyleMain FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':checkstyleMain'.
> Unable to create a Checker: Property 'fileExtensions' in module Checker does not exist, please check the documentation

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

Total time: 1.782 secs

It is said that fileExtensions does not exist.

Comment out and run

Comment out the relevant part and try executing it.

Run


$ gradle check

:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:checkstyleMain
[ant:checkstyle] project\src\main\java\jp\toastkid\libs\tinysegmenter\CharacterClassifier.java:0: Missing package-info.java file.
[ant:checkstyle] project\src\main\java\jp\toastkid\libs\tinysegmenter\CharacterClassifier.java:0:The file does not end with a new line.

……(Omitted because there are too many points)……

[ant:checkstyle] project\src\main\java\jp\toastkid\ratpack\models\WordCloud.java:79:58: 'str'To@Requires param tag.
:checkstyleMain FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':checkstyleMain'.
> Checkstyle rule violations were found. See the report at: project/build/reports/checkstyle/main.html

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

Total time: 3.639 secs

Well, the code I prepared this time was really terrible ... Even with this plugin, if ignoreFailures is false, the build will fail if a warning is issued. The report has been generated so let's take a look.

Report

Report files are generated in html and xml under `` `build / reports / checkstyle / ```.

cs.png

: warning: Don't treat build as a failure even if there are too many indications

If you add ignoreFailures = true to this plugin as well, the build will not be treated as a failure no matter how many warnings are issued.

build.gradle


checkstyle {
  ignoreFailures = true

reference

-Chapter 29 Checkstyle Plugin


JaCoCo It is a plugin that outputs a test report. You can measure test coverage and see it visually. The name seems to be the acronym of "** Ja ** va ** Co ** de ** Co ** verage".

Introduction

Add the JaCoCo plugin to build.gradle.

build.gradle


apply plugin: "jacoco"

Run

The test build must be running. This time, run it with `$ gradle test jacocoTestReport`.

Run


$ gradle test jacocoTestReport

:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:compileTestJava
:processTestResources UP-TO-DATE
:testClasses
:test
:jacocoTestReport

BUILD SUCCESSFUL

Total time: 3.448 secs

Report

By default, test reports are generated in HTML format at ``` build / reports / jacoco / test / html / index.html` ``.

packages jacoco.png

classes jacoco2.png

methods jacoco3.png

It becomes finer in the order of packages-> classes-> methods.

Details

jacoco4.png

When you select a method name, a green background shows which part of the class was called from the test code, and a red background shows where it didn't pass. It's very easy to understand.

reference


JDpend It seems to be a tool for static analysis on a package-by-package basis.

Introduction

build.gradle


apply plugin: 'jdepend'

Run

$ gradle jdependmainRun with.

Run


$ gradle jdependMain

:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:jdependMain
Download https://repo1.maven.org/maven2/jdepend/jdepend/2.9.1/jdepend-2.9.1.pom
Download https://repo1.maven.org/maven2/org/apache/ant/ant-jdepend/1.9.6/ant-jdepend-1.9.6.pom
Download https://repo1.maven.org/maven2/org/apache/ant/ant-parent/1.9.6/ant-parent-1.9.6.pom
Download https://repo1.maven.org/maven2/jdepend/jdepend/2.9.1/jdepend-2.9.1.jar
Download https://repo1.maven.org/maven2/org/apache/ant/ant-jdepend/1.9.6/ant-jdepend-1.9.6.jar
[ant:jdependreport] ependMain

[ant:jdependreport] Unknown constant: 18

BUILD SUCCESSFUL

Total time: 3.719 secs

Report

The report file is generated in XML format in build / reports / jdepend.

Don't treat build as a failure even if there are too many indications

If you add ignoreFailures = true to this plugin as well, the build will not be treated as a failure no matter how many warnings are issued.

build.gradle


JDepend {
  ignoreFailures = true

reference

-Chapter 32 JDepend Plugin


Project report plugin

It has nothing to do with static analysis tools, but I learned that there seems to be such a plugin, so I will try it.

Introduction

Add the plugin to build.gradle.

build.gradle


apply plugin: 'project-report'

Run

$ gradle projectreportGenerate all reports with.

Run


$ gradle projectReport

:dependencyReport
:htmlDependencyReport
:propertyReport
:taskReport
:projectReport

BUILD SUCCESSFUL

Total time: 1.472 secs

Report

build/reports/project/dependencies/root.It is output to html. JavaScript execution permission is required to display.



 ![projectReport.png](https://qiita-image-store.s3.amazonaws.com/0/102004/afbec792-774d-583f-ce7f-50f8aad62ea9.png)


 It shows not only application compilation dependencies but also plugin dependencies. If the text format is good, it is generated in `` `build / reports / project / dependencies.txt` ``, so you should refer to that.

## reference
 -[Chapter 41 Project Report Plugin](http://gradle.monochromeroad.com/docs/userguide/project_reports_plugin.html)

----
 [License Gradle Plugin](https://github.com/hierynomus/license-gradle-plugin)
 It's not a standard plugin, but I found it easy and useful to install, so I'll write about it. This is a plugin that traces the project license to the dependency and outputs it to the report.
 Depending on the company, it may be necessary to check the license before using the OSS library or before releasing the deliverable, but if you have trouble following pom.xml one by one at such times, consider introducing this plugin You may try it.

## Introduction
 [Output the license list of dependencies with gradle](http://blog.olivinecafe.info/post/105264504040/gradle%E3%81%A7dependencies%E3%81%AE%E3%83%A9%E3%82% A4% E3% 82% BB% E3% 83% B3% E3% 82% B9% E4% B8% 80% E8% A6% A7% E3% 82% 92% E5% 87% BA% E5% 8A% 9B% If you refer to E3% 81% 99% E3% 82% 8B), you can install it immediately.

 Specifically, add the following to build.gradle and you're ready to go.


#### **`build.gradle`**
```groovy

apply plugin: "com.github.hierynomus.license"

......

buildscript {
  repositories {
    maven {
      url "https://plugins.gradle.org/m2/"
    }
  }
  dependencies {
    classpath "gradle.plugin.nl.javadude.gradle.plugins:license-gradle-plugin:0.13.1"
  }
}

Run

$ gradle downloadlicensesPlease run the.

Run


$ gradle downloadLicenses

:downloadLicenses

BUILD SUCCESSFUL

Total time: 10.753 secs

Report

build/reports/license/Two types of html and xml are generated in the folder, for a total of four files.

file name Description
license-dependency Summary by license
dependency-license Summary by dependency unit

license-dependency license2.png

dependency-license license1.png

`License-dependency``` is useful for checking for GPL-based licenses, and `dependency-license``` is recommended if you need to look up individual licenses. ..

reference

-[Output the license list of dependencies with gradle](http://blog.olivinecafe.info/post/105264504040/gradle%E3%81%A7dependencies%E3%81%AE%E3%83%A9%E3%82 % A4% E3% 82% BB% E3% 83% B3% E3% 82% B9% E4% B8% 80% E8% A6% A7% E3% 82% 92% E5% 87% BA% E5% 8A% 9B % E3% 81% 99% E3% 82% 8B)


Summary

I introduced how to use a static analysis tool that can be easily used from the Gradle plugin. It is important that these tools are automatically executed on a regular basis through CI, rather than being executed by typing commands each time.

sample

-This sample project

Folder hierarchy of the report generated this time

Folder hierarchy(tree&nbsp;/f)


build
  │
  └─reports
      ├─jacoco
      │  └─test
      │      └─html
      │          │  index.html
      │          │  jacoco-sessions.html
      │          │
      │          ├─jacoco-resources
      │          │      branchfc.gif
      │          │      branchnc.gif
      │          │      branchpc.gif
      │          │      bundle.gif
      │          │      class.gif
      │          │      down.gif
      │          │      greenbar.gif
      │          │      group.gif
      │          │      method.gif
      │          │      package.gif
      │          │      prettify.css
      │          │      prettify.js
      │          │      redbar.gif
      │          │      report.css
      │          │      report.gif
      │          │      session.gif
      │          │      sort.gif
      │          │      sort.js
      │          │      source.gif
      │          │      up.gif
      │          │
      │          ├─jp.toastkid.libs.tinysegmenter
      │          │      CharacterClassifier.html
      │          │      CharacterClassifier.java.html
      │          │      index.html
      │          │      index.source.html
      │          │      ScoreMap.html
      │          │      ScoreMap.java.html
      │          │      TinySegmenter.html
      │          │      TinySegmenter.java.html
      │          │
      │          ├─jp.toastkid.ratpack
      │          │      index.html
      │          │      index.source.html
      │          │      Main.html
      │          │      Main.java.html
      │          │
      │          └─jp.toastkid.ratpack.models
      │                  index.html
      │                  index.source.html
      │                  WordCloud.html
      │                  WordCloud.java.html
      │
      ├─license
      │      dependency-license.html
      │      dependency-license.xml
      │      license-dependency.html
      │      license-dependency.xml
      │
      ├─pmd
      │      main.html
      │      main.xml
      │
      ├─project
      │  │  dependencies.txt
      │  │  properties.txt
      │  │  tasks.txt
      │  │
      │  └─dependencies
      │      │  index.html
      │      │  root.html
      │      │  root.js
      │      │
      │      ├─css
      │      │      base-style.css
      │      │      style.css
      │      │      tree.css
      │      │
      │      ├─images
      │      │      d.gif
      │      │      d.png
      │      │      throbber.gif
      │      │
      │      └─js
      │              jquery.jstree.js
      │              jquery.min-1.11.0.js
      │              script.js
      │
      └─tests
          └─test
              │  index.html
              │
              ├─classes
              │      jp.toastkid.ratpack.models.WordCloudTest.html
              │
              ├─css
              │      base-style.css
              │      style.css
              │
              ├─js
              │      report.js
              │
              └─packages
                      jp.toastkid.ratpack.models.html

Recommended Posts

Use static analysis tools in your Gradle project
Static code analysis with Checkstyle in Java + Gradle
Automatically specify version in gradle project
Run static analysis Infer in Windows environment
Run modular project tests in Gradle (JUnit5 + TestFX)
Java tips-Create a Spring Boot project in Gradle
Add a project in any folder with Gradle
Use pagy for pagination in your Rails app.
View the Gradle task in the Spring Boot project
Add an external jar file in your IntelliJ project.