How to compile project with Google Checkstyle rules with gradle? - java

I am trying to use Google checkstyle configuration (https://github.com/checkstyle/checkstyle/blob/master/src/main/resources/google_checks.xml) but I am constantly getting an error on gradle check:
Unable to create a Checker: cannot initialize module TreeWalker - Unable to instantiate EmptyCatchBlock
I used Gradle to build the project. Below is my gradle.build.
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'checkstyle'
sourceCompatibility = 1.8
version = '1.0'
checkstyle {
toolVersion = "6.3"
}
task "create-dirs" << {
sourceSets*.java.srcDirs*.each { it.mkdirs() }
sourceSets*.resources.srcDirs*.each { it.mkdirs() }
}
jar {
manifest {
attributes 'Implementation-Title': 'xyz',
'Implementation-Version': 0.01
}
}
repositories {
mavenCentral()
}
dependencies {
compile (
['org.apache.logging.log4j:log4j-api:2.2'],
['org.apache.logging.log4j:log4j-core:2.2']
)
testCompile(
['junit:junit:4.11'],
['org.mockito:mockito-core:1.+']
)
}
test {
systemProperties 'property': 'value'
}
uploadArchives {
repositories {
flatDir {
dirs 'repos'
}
}
}
Also, when I try to add XML config file to Checkstyle plugin in IDEA I get similar error but with a stack trace:
org.infernus.idea.checkstyle.exception.CheckStylePluginException: <html><b>The CheckStyle rules file could not be loaded.</b><br>cannot initialize module TreeWalker - Unable to instantiate EmptyCatchBlock</html>
at org.infernus.idea.checkstyle.checker.CheckerFactory.blacklistAndShowMessage(CheckerFactory.java:234)
at org.infernus.idea.checkstyle.checker.CheckerFactory.createChecker(CheckerFactory.java:188)
at org.infernus.idea.checkstyle.checker.CheckerFactory.getOrCreateCachedChecker(CheckerFactory.java:98)
at org.infernus.idea.checkstyle.checker.CheckerFactory.getChecker(CheckerFactory.java:73)
at org.infernus.idea.checkstyle.checker.CheckerFactory.getChecker(CheckerFactory.java:41)
I cannot figure out what am I doing wrong. Any help would be appreciated.
Gradle version: 2.2

You can add this configuration into your build.gradle file:
configurations {
checkstyleOverride
}
dependencies {
checkstyleOverride('com.puppycrawl.tools:checkstyle:6.11.2')
}
tasks.withType(Checkstyle) {
checkstyleClasspath = project.configurations.checkstyleOverride
}
Enjoy!

The problem lies in the fact that com.puppycrawl.tools.checkstyle.checks.blocks.EmptyCatchBlockCheck was indeed added to checkstyle but for version 6.4-SNAPSHOT. As it can be seen in checkstyle repository (pom.xml history) version 6.4-SNAPSHOT was introduced on the 02.02.2015 and EmptyCatchBlockCheck class was created on 18.02.2015.
Gradle still uses version 6.3 as in the following log extract:
:checkstyleMain
Download https://repo1.maven.org/maven2/com/puppycrawl/tools/checkstyle/6.3/checkstyle-6.3.pom
So there's simply no class You'd like to use.
According to the docs checkstyle classpath can be specified with checkstyleClasspath property - you can try to set it up manually.
I've also prepared a demo with 6.4-SNAPSHOT version, it can be found here. Checkstyle jar was built with mvn clean package with source taken from this repo.

Here is an approach that works with the (currently) latest versions of Gradle & Checkstyle (Gradle 6.1.1 & Checkstyle 8.29):
plugins {
id 'java'
id 'checkstyle'
}
configurations {
checkstyleConfig
}
dependencies {
checkstyleConfig("com.puppycrawl.tools:checkstyle:8.29") { transitive = false }
}
checkstyle {
toolVersion '8.29'
config = resources.text.fromArchiveEntry(configurations.checkstyleConfig, 'google_checks.xml')
}
Note that the Checkstyle dependency excludes transitive dependencies, otherwise the resources.text.fromArchiveEntry will fail since multiple JAR files will be present, and it will be unable to select a single one.

Related

How do you parameterize the Spring Boot Gradle plugin?

We are looking to migrate from Maven to Gradle, and have worked through most of the challenges you would expect for replacing the parent POM concept. There is one sticky point that we haven't figured out yet. We need to specify the version of Spring Boot we are using globally, but I run into invalid build file problems with both of the solutions I've tried:
I tried putting the plugins { id 'org.springframework.boot' version '2.1.17.RELEASE' } declaration in the common build script. Build error, "Only Project and Settings build scripts can contain plugins {} blocks."
I tried calling the common build file to specify the springBootVersion parameter and using that in the plugins declaration. Build Error, "only buildscript {} and other plugins {} script blocks are allowed before plugins {} blocks, no other statements are allowed"
All of this would be easier if I could simply apply plugin: 'org.springframework.boot' but then Gradle can't find the plugin. All but one microservice are on a single version of Spring Boot, and we want to be able to upgrade globally if possible.
Additional Information
I have ~40 microservices plus some libraries used by those services
Separate repository for each of them, so the normal parent/child approach does not work
Maven parent POMs allowed you to publish that POM as it's own resource, and there is no 1:1 equivalent feature in Gradle
Gradle pluginManagement concept also doesn't work for us because it resolves the Spring Boot plugin but the dependency management plugin now can't be found.
My common build script is included here:
repositories {
mavenLocal()
/* Removed our internal repositories */
jcenter()
mavenCentral()
}
apply plugin: 'java'
apply plugin: 'jacoco'
apply plugin: 'maven-publish'
apply plugin: 'io.spring.dependency-management'
group = 'nedl-unified-platform'
/* Required to publish Spring Boot microservices to publish to repository */
configurations {
[apiElements, runtimeElements].each {
it.outgoing.artifacts.removeIf { it.buildDependencies.getDependencies(null).contains(jar) }
it.outgoing.artifact(bootJar)
}
}
java {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
withJavadocJar()
withSourcesJar()
}
ext {
set('springBootVersion', '2.1.17.RELEASE')
set('springCloudVersion', "Greenwich.SR6")
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}
jacoco {
toolVersion = "0.8.5"
reportsDir = file("$buildDir/reports/jacoco")
}
test {
finalizedBy jacocoTestReport // report is always generated after tests run
}
jacocoTestCoverageVerification {
violationRules {
rule {
limit {
minimum = 0.2
}
}
}
}
jacocoTestReport {
dependsOn test // tests are required to run before generating the report
reports {
xml.enabled true
html.destination file("${reportsDir}/jacocoHtml")
xml.destination file("${reportsDir}/jacocoReport.xml")
}
}
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
publishing {
publications {
maven(MavenPublication) {
from components.java
}
}
repositories {
/* excluded for privacy and brevity's sake, our internal Maven repo */
}
}
And that is called by our project build script that I want to parameterize:
plugins {
id 'org.springframework.boot' version springBootVersion
}
apply from: "https://mycentral.repo/project-common/develop/build.gradle"
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-server'
implementation 'ch.qos.logback:logback-classic'
implementation 'javax.annotation:javax.annotation-api:1.3.2'
implementation 'javax.xml.bind:jaxb-api:2.4.0-b180830.0359'
implementation 'org.glassfish.jaxb:jaxb-runtime:2.4.0-b180830.0438'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
version = '0.0.2-SNAPSHOT'
I think the gap here is that in maven you have the concept of a parent pom, whereas in Gradle you don't. There is no 1:1 mapping to this like you say, but you can have plugins in Gradle, and apply a plugin.
The closest thing you would have is if you developed your own Gradle plugin, which each of your projects could apply. Your custom plugin would then configure Spring Boot among whatever else is common to all your projects. This plugin would define the version of Spring Boot you want all your other projects to use.
You wouldn't get much benefit to a custom plugin if it's only concern is configuring Spring Boot, it would need to do other things as well. It can be difficult to create a Gradle plugin when you don't have allot of experience in it. You lose all the familiar syntax to the build.gradle and you literally have to write code, (there are some similarities but I have found it difficult), I would avoid it if possible.
I would suggest you start off by applying the spring boot plugin directly to one of your microservices projects, get that working, then do another. After you have done a number of them you will then be able to see what is common between them, and if it is indeed worth investing into developing a global plugin. You really need to be careful though because your global plugin has the potential to be both a blessing and curse. It may take away allot of manual work for maintainers, but if you get it wrong it will cause them grief, and then they will want to go back to maven.
I'm not sure if I understand your globally defined Spring version requirement. Unless you are using SNAPSHOT dependencies/plugins (bad don't do that), (or a black magic settings.gralde outside of your repo), you will have to put some version somewhere. As an alternative you could create your own custom task which runs on the check lifecycle which will check the version of spring (or your plugin) and print a warning if it's not the latest version, and encourage the developer to upgrade.
Extra Info
Parameterizing plugins with properties can be done putting your property in gradle.properties as springBootVersion=2.1.17.RELEASE .
I'm not sure I understood your issue perfectly but you should use the Gradle way for sharing configuration : the root project config.
Instead of including the common build script in every project, create a global project and set the configuration here.
root
|
| --- projectA
| --- projectB
| --- projectC
With the according settings.gradle
include 'projectA'
include 'projectB'
include 'projectC'
In the root build.gradle, set up the version
ext.springBootVersion = '2.1.17.RELEASE'
In subprojects using springBoot, let's say projectB, apply the plugin in the sub build.gradle
buildscript {
repositories {
jcenter()
mavenCentral()
}
dependencies {
classpath "org.springframework.boot:spring-boot-gradle-plugin:$springBootVersion"
}
}
apply plugin: 'org.springframework.boot'
This example works for me, though I may not understand all of the constraints.
If we abstract the version of Spring Boot behind a fixed URI (e.g. on an internal CI/CD server), then consider this in each project/repo's build.gradle:
buildscript {
repositories {
jcenter()
}
def SPRING_BOOT_VERSION_URI = 'http://localhost:5151/api-server/spring-boot.txt'
ext.springBootVersion = new URL(SPRING_BOOT_VERSION_URI).getText().trim()
dependencies {
classpath "org.springframework.boot:spring-boot-gradle-plugin:$springBootVersion"
}
}
apply plugin: 'org.springframework.boot'
apply from: "../common/build.gradle"
I realize the original question states that the apply plugin doesn't work, but it's not clear to me if that precludes this method.
Finally, note that it is easy to expand this beyond a simple text-file to be a more formal JSON specification (tailored to the teams' needs).
If you add this to the root project, all child projects should be able to just import from the same set of Spring Boot dependencies. The magic ingredient is the allprojects block:
buildscript {
repositories {
maven { url "https://plugins.gradle.org/m2/" }
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
ext {
springBootVersion = '2.3.4.RELEASE'
}
allprojects {
apply plugin: 'java'
apply plugin: 'io.spring.dependency-management'
dependencyManagement {
imports {
mavenBom("org.springframework.boot:spring-boot-dependencies:${springBootVersion}")
}
}
}
apply plugin: 'org.springframework.boot'

Resolve findBugs issue in gradle

Overview:
I am trying to upgrade Java and Gradle version in my project as follows:
java from 8 to 11
Gradle from 5 to 6
My project runs with no issues on the old versions but when runs on Java 11 and Gradle 6 it complains about fireBugs plugin and raises the following exception:
> Plugin with id 'findbugs' not found.
Snippet of gradle file:
buildscript {
ext {
SampleProjectVersion = '1.3.4'
}
repositories {
mavenLocal()
maven {
url1
}
}
dependencies {
classpath(sample lib 1)
classpath(sample lib 2)
}
apply plugin: 'findbugs'
...
I would appreciate if you could share your thoughts with me as I couldn't find any proper solution for that.
From the Gradle web site (Upgrading your build from Gradle 5.x to 6.0):
The FindBugs plugin has been removed
The deprecated FindBugs plugin has been removed. As an alternative,
you can use the SpotBugs plugin from the Gradle Plugin Portal.
https://docs.gradle.org/current/userguide/upgrading_version_5.html
You can use the SpotBugs plugin. Try my snippet of gradle file
buildscript {
ext {
SampleProjectVersion = '1.3.4'
}
repositories {
mavenLocal()
maven {
url1
}
}
dependencies {
classpath(sample lib 1)
classpath(sample lib 2)
classpath "gradle.plugin.com.github.spotbugs:spotbugs-gradle-plugin:2.0.0"
}
apply plugin: "com.github.spotbugs"
tasks.withType(com.github.spotbugs.SpotBugsTask) {
spotbugsMain.enabled = true
spotbugsTest.enabled = true
reports {
xml.enabled = false
html.enabled = true
}
}
...

Gradle building Spring Boot library without Main Class

I am trying to build a Spring Boot/Gradle project and create a jar without a main class. My purpose is that this project is a library that will be pulled in by other projects therefore the library project does not require a main class to run. Unfortunately, no matter what kind of gradle config I write I keep getting errors when I try to build install about not having a main class or not being able to find the bootJar task.
Here's what my gradle file looks like:
plugins {
id 'org.springframework.boot' version '2.1.7.RELEASE' apply false
}
apply plugin: 'io.spring.dependency-management'
apply plugin: 'maven'
dependencyManagement {
imports {
mavenBom org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES
}
}
repositories {
mavenCentral()
}
jar {
enabled = true
}
bootJar.dependsOn fooTask
But when I run this I get the following error:
Could not get unknown property 'bootJar' for root project
'foo-library' of type org.gradle.api.Project.
What in my configuration needs to change?
Disable bootJar in your build.gradle
bootJar {
enabled = false
}

Using protobuf with Gradle (IntelliJ)

I am trying to generate code for a simple protobuf example using the build instructions given here. I have been trying for awhile but I am not able to see any auto generated code in my source root.
The following is my build.gradle file
buildscript {
ext {
springBootVersion = '2.0.4.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
classpath "io.spring.gradle:dependency-management-plugin:1.0.3.RELEASE"
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.5'
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
apply plugin: 'com.google.protobuf'
group = 'io.ai.vivid'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencyManagement {
imports {
mavenBom 'com.amazonaws:aws-java-sdk-bom:1.11.228'
}
}
protobuf {
protoc {
artifact = "com.google.protobuf:protoc:3.5.1-1"
}
generateProtoTasks.generatedFilesBaseDir = 'generated-sources'
plugins {
grpc {
artifact = 'io.grpc:protoc-gen-grpc-java:1.14.0'
}
}
generateProtoTasks {
all()*.plugins {
grpc {}
}
}
}
dependencies {
compile 'io.grpc:grpc-netty-shaded:1.14.0'
compile 'io.grpc:grpc-protobuf:1.14.0'
compile 'io.grpc:grpc-stub:1.14.0'
}
Also in my build.gradle file IntelliJ complains that it cannot resolve name protobuf
Things I have tried
Sync gradle tool in IntelliJ. This is the most prominent solution
given in SO
Setting Build tools -> Gradle -> Runner -> Delelgate IDE build/run
actions on gradle to true
Clean rebuilding of the gradle project.
From my understanding of the GitHub post, when you use the protobuf plugin, the stub will be automatically generated for you. What am I missing?
You've applied idea plugin, but you didn't configure it. You need to tell idea plugin where to include the generated source code.
protobuf {
generatedFilesBaseDir = "$projectDir/src/generated"
}
idea {
module {
sourceDirs += file("${projectDir}/src/generated/main/java");
sourceDirs += file("${projectDir}/src/generated/main/grpc");
}
}
You can take a look
at a full example of a buildfile here: build.gradle
In case anyone else ends up here problems getting IntelliJ to recognise the generated sources (Red highlight imports , classes etc). Beware of the intellisense file size limit. If your generated protobuf code exceeds the default setitng of 2500KB then the file is ignored.
Got Help -> Edit custom properties and add an entry appropriate for your case e.g.
idea.max.intellisense.filesize=4000
Spent half a day faffing over different source set source folder, generated sources, and include / exclude directories. Turned out I just need to increase this value
Alternatively, you can use sourceSets:
sourceSets {
main {
java {
srcDirs 'build/generated/source/proto/main/grpc'
srcDirs 'build/generated/source/proto/main/java'
}
}
}

Could not set unknown property 'mainClass' for object of type org.springframework.boot.gradle.dsl.SpringBootExtension

I have the main build.gradle file for the project
buildscript {
repositories {
jcenter()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${spring_boot_version}")
}
}
def javaProjects = subprojects.findAll {
it.name in ["common", "core", "web", "app"]
}
allprojects {
apply plugin: 'idea'
apply plugin: 'eclipse'
repositories {
jcenter()
}
}
idea {
project {
jdkName = "1.8"
languageLevel = "1.8"
vcs = "Git"
}
}
configure(javaProjects) {
apply plugin: 'java'
apply plugin: 'io.spring.dependency-management'
apply plugin: 'findbugs'
sourceCompatibility = 1.8
targetCompatibility = 1.8
dependencies {
...
}
}
and the build.gradle file for the app module, where I have a configuration to run gradle
apply plugin: 'org.springframework.boot'
dependencies {
...
}
springBoot {
mainClass = "com.web.WebApplication"
}
jar {
manifest {
attributes 'Implementation-Title': "Rest-Web-Services",
'Implementation-Version': "1.0",
'Main-Class': "com.web.WebApplication"
}
}
when build gradle throws
FAILURE: Build failed with an exception.
* Where:
Build file '...\REST-Web-Services\app\build.gradle' line: 28
* What went wrong:
A problem occurred evaluating project ':app'.
> Could not set unknown property 'mainClass' for object of type org.springframework.boot.gradle.dsl.SpringBootExtension.
How to set the startup mainClass class?
Configuring the main class
By default, the executable archive’s main class will be configured automatically by looking for a class with a public static void main(String[]) method in directories on the task’s classpath.
The main class can also be configured explicitly using the task’s mainClassName property:
bootJar {
mainClassName = 'com.example.ExampleApplication'
}
Alternatively, the main class name can be configured project-wide using the mainClassName property of the Spring Boot DSL:
springBoot {
mainClassName = 'com.example.ExampleApplication'
}
If the application plugin has been applied its mainClassName project property can be used for the same purpose:
mainClassName = 'com.example.ExampleApplication'
Lastly, the Start-Class attribute can be configured on the task’s manifest:
bootJar {
manifest {
attributes 'Start-Class': 'com.example.ExampleApplication'
}
}
Refrance
Basically, this is about spring-boot gradle plugin:
bevore verion springboot2, it useed mainClass property,
since v2.0.0.RELEASE, it changed to use mainClassName.
I followed the Spring Restful Service tutorial that does not have the declaration,and it worked. Try removing the mainClass declaration.
The Spring Boot gradle plugin provides many convenient features:
It collects all the jars on the classpath and builds a single, runnable "über-jar", which makes it more convenient to execute and transport your service.
It searches for the public static void main() method to flag as a runnable class.
It provides a built-in dependency resolver that sets the version number to match Spring Boot dependencies. You can override any version you wish, but it will default to Boot’s chosen set of versions.
TL;DR
Define following block in you Gradle build script:
springBoot {
mainClass = 'com.example.ExampleApplication'
}
Error
With the org.springframework.boot Gradle plugin version 2.6.2.
plugins {
id 'org.springframework.boot' version '2.4.0'
}
I had similar issue.
Execution failed for task ':bootJar'.
Failed to calculate the value of task ':bootJar' property 'mainClass'.
Main class name has not been configured and it could not be resolved
Spring has again changed convention of how to provide main class since #leo has provided an answer for this reason I will extend it. Now depending on the version of the springframework.boot plugin you have to define the main class value on following way (sorted from newest to oldest):
SpringFramework 2.4.0 and newer
springBoot {
mainClass = 'com.example.ExampleApplication'
}
Release/Migration notes for 2.4.0
SpringFramework 2.3.12 and older
springBoot {
mainClassName = 'com.example.ExampleApplication'
}
Release/Migration notes for 2.0.0
SpringFramework 1.5.22.RELEASE and older (Hopefully you are not using that anymore)
bootRepackage {
mainClass = 'demo.Application'
}

Categories

Resources