DevNexus 2018 – Gradle – the basics and beyond

Title: Gradle – the Basics and Beyond
Speakers: Ken Kousen

For more blog posts, see the DevNexus 2018 live blogging table of contents


Install

  • requires Java 7+
  • Gradle 4.2.1+ supports Java 9
  • Gradle releases frequently but is very backward compatible
  • Just unzip and add to path
  • The complete distribute includes the samples. The sample sources are also available online.

General

  • Gradle is now much faster than Maven
  • gradle.com is the enterprise version which is built on top of open source gradle.org.
  • Gradle is mostly implemented in Java. Groovy is for the DSL.
  • Uses Ant behind the scenes as well
  • Groovy comes with Gradle. Don’t need to install Groovy separately
  • gretty is jetty for gradle; also contains tomcat

Docs

Future

  • Kotlin
    • Creating a Kotlin DSL for simple build files.
    • Kotlin is not replacing Groovy
    • Not yet at 1.0.0
    • Goal is better IDE integration
  • Generator
    • Looking at being able to generate projects on web project like Spring Boot has

gradlew

  • Recommend using gradlew. Checking in the file guarantees users are on version of gradle that you intended
  • Has effect of creating many gradle installs on your machine. Not that big.

Creating a project

  • Can generate new project or port basic pom files.
  • Use porting as a guide and then hand edit
  • Generate new project in current directory (make empty directory by hand first)
    • mkdir proj
    • cd proj
    • gradle init –type java-application (or java-library)
  • Files/directories in project
    • gradlew/gradlew.bat – wrapper script
    • gradle/wrapper – jar and properties
    • settings.gradle – lists multi project builds
    • gradle.properties – key/value pairs used by build
  • In home directory’x .gradle
  • wrapper/distx – the binarry/installs.

Daemon

  • Improves performance
  • Cache a lot of the JVM startup
  • For a few hours, same daemon used if using same version of gradle on every project.
  • Tip: turn off daemon on CI servers so every build is a clean build

Gradle file

  • repositories
    • can use jcenter or maven central.
    • or can specify a different one for any Maven or Ivy repo; like internal corporate one
    • can list multiple repos and searches in order
  • dependencies
    • ‘group:name:version’ – same concept as Maven GAV. Or can split into three sections. Ken likes the former better; either fine.
    • can write compile (‘g:n:v’) to specify fully. Groovy parens are optional except when they are not. The DSL can interpret without parens and easier to read.
    • New Java plugin has api/implementation to use as scope instead of compile.
    • compile files – lets you add files not in the classpath
    • compile fileTree – lets you add a directory not in the classpath
  • plugins
    • if registered on plugins.gradle.org, can list id and version numbers.
    • built in plugins (ex: java) don’t get a version number

Commands

  • gradle build -t – rebuilds and then sits idle until you change code. Like a rebuild loop
  • gradle build –dry-run – shows what would run (can use -m instead of –dry-run)
  • gradle -b… – use different build file name
  • gradle –stsatus – shows processes

Build scan

  • Starting Gradle 4.3, will prompt you if you haven’t accepted the license agreement and try to use.
  • It’s hosted at Gradle so sends some info out.
  • Gradle Enterprise does build scans in house

My take

Good structured intro/review. Happy that Ken changed the background to white when we were reading code. He also made the code sufficiently large. I didn’t even need my glasses. Go Ken! The only time I needed my classes was when he showed the manual which uses dark gray on a light gray background for the comments. I knew more of the basics than I realized. But good to have it gel better in my head! And I definitely learned things. Rushed at the end though and that was where most of the new stuff is. Glad I’m a New Yorker and can handle talking fast. Can’t type that fast though so stopped taking notes.

junit 5, gradle and containers

Up until recently, I’ve been using JUnit 5 with Eclipse and Maven. As I started using it with Gradle, I became frustrated that you couldn’t see the number of tests run when the tests succeeded. (Don’t worry; this is an easily solvable problem.)

First JUnit 4

You can add code to have Groovy print the number of tests. This matches the number of tests that Eclipse/Maven say are run.

test {
   afterSuite { desc, result ->
    	     if (!desc.parent)
        		println("${result.resultType} " +
            "(${result.testCount} tests, " +
            "${result.successfulTestCount} successes, " +
            "${result.failedTestCount} failures, " +
            "${result.skippedTestCount} skipped)")
   }
}

On to JUnit 5
It’s even less code to ask JUnit 5 to print the test results:

junitPlatform {
  details 'tree'
}

This prints something like

Test run finished after 2518 ms
 [ 20 containers found ]
 [ 0 containers skipped ]
 [ 20 containers started ]
 [ 0 containers aborted ]
 [ 20 containers successful ]
 [ 0 containers failed ]
 [ 27 tests found ]
 [ 1 tests skipped ]
 [ 26 tests started ]
 [ 0 tests aborted ]
 [ 26 tests successful ]
 [ 0 tests failed ]

I agree that I have 27 tests with 1 skipped. But what’s this 20 containers? As you can see from the tree, we have:

  • 1 – JUnit Vintage – to run the JUnit 3/4 tests
  • 1 – JUnit Jupiter – to run the JUnit 5 tests (I didn’t have any in the project at the time I captured this tree so it is an empty container; but still counts)
  • 9 – JUnit test classes
  • 9 – The nine data elements in my parameterized test.

├─ JUnit Vintage ✔
│ ├─ com.devnexus.workshop.junit5.CentennialOlympicParkTest ✔
│ │ ├─ oldestForFirstElement ✔
│ │ ├─ oldestForLastElement ✔
│ │ ├─ oldestForEmptyList ✔
│ │ └─ url ✔
│ ├─ com.devnexus.workshop.junit5.EarthquakeTimeoutTest ✔
│ │ └─ timeout ✔
│ ├─ com.devnexus.workshop.junit5.ParkBuildingTest ✔
│ │ ├─ equalsValues ✔
│ │ └─ hashCodeValues ✔
│ ├─ com.devnexus.workshop.junit5.EarthquakeTest ✔
│ │ ├─ usingStandalone ✔
│ │ ├─ noMessageChecking ✔
│ │ └─ usingRule ✔
│ ├─ com.devnexus.workshop.junit5.GeorgiaAquariumTest ✔
│ │ ├─ namesOfShows ✔
│ │ └─ numberLines ✔
│ ├─ com.devnexus.workshop.junit5.OlympicsDatesTest ✔
│ │ ├─ [1996-07-19] ✔
│ │ │ └─ date[1996-07-19] ✔
│ │ ├─ [1996-07-20] ✔
│ │ │ └─ date[1996-07-20] ✔
│ │ ├─ [1996-07-31] ✔
│ │ │ └─ date[1996-07-31] ✔
│ │ ├─ [1996-08-03] ✔
│ │ │ └─ date[1996-08-03] ✔
│ │ ├─ [1996-08-04] ✔
│ │ │ └─ date[1996-08-04] ✔
│ │ ├─ [1996-07-18] ✔
│ │ │ └─ date[1996-07-18] ✔
│ │ ├─ [1996-08-05] ✔
│ │ │ └─ date[1996-08-05] ✔
│ │ ├─ [1997-07-18] ✔
│ │ │ └─ date[1997-07-18] ✔
│ │ └─ [1995-08-01] ✔
│ │ └─ date[1995-08-01] ✔
│ ├─ com.devnexus.workshop.junit5.CentennialOlympicParkEnumTest ✔
│ │ └─ allClosingTimesAfter9pm ✔
│ ├─ com.devnexus.workshop.junit5.ShakeExceptionTest ✔
│ │ └─ message ↷ this test is ignored becuase it is unnecessary
│ └─ com.devnexus.workshop.junit5.GeorgiaAquariumWaitTest ✔
│ ├─ plentyOfTime ✔
│ ├─ exactOpening ✔
│ ├─ anyMinuteNow ✔
│ └─ alreadyOpen ✔
└─ JUnit Jupiter ✔

Test run finished after 2518 ms
[ 20 containers found ]
[ 0 containers skipped ]
[ 20 containers started ]
[ 0 containers aborted ]
[ 20 containers successful ]
[ 0 containers failed ]
[ 27 tests found ]
[ 1 tests skipped ]
[ 26 tests started ]
[ 0 tests aborted ]
[ 26 tests successful ]
[ 0 tests failed ]

 

getting started with gradle in eclipse on a mac

I’ve used Gradle before although not a ton. For example, I compared eGradle and Buildship here. It’s been a while though. Which means my laptop setup has changed enough for it to be an adventure. (and not everything I needed to know was in my memory).

Eclipse Oxygen comes with Gradle installed so I thought this would be easy. And if I had never installed Java 9 on my computer, that would have been the case. After all, you just need to run: File > New > Gradle Project

The original problem

I tried that and got this error:

org.gradle.tooling.GradleConnectionException: Could not fetch model of type ‘BuildEnvironment’ using Gradle distribution ‘https://services.gradle.org/distributions/gradle-3.5-bin.zip’.

Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make protected java.lang.Package[] java.lang.ClassLoader.getPackages() accessible: module java.base does not “opens java.lang” to unnamed module @2e59aa

I got a similar error when trying to import an existing Gradle project. I have Gradle installed on the command line and it works fine.

What didn’t work 

I want to be using Java 8. I tried the following things that didn’t help:

  • Change eclipse.ini to use Java 8
  • Remove all Java 9 JDKs from the Eclipse workspace preferences.
  • Adding a system JAVA_HOME environment variable pointing to Java 8
  • This workaround editing the build.gradle file
  • A new workspace (my teammate teases me that my workspace was around when Obama got elected – I often do an upgrade in place)
  • Gradle code for Eclipse
  • Checked my versions against what is known to work. I do have Buildship 2.2+ (2.2.1) and Gradle 4.3+ (gradle 4.5).
  • Re-installing Eclipse and not installing/updating any plugins

Updating the plugin

Then I updated the Buildship plugin in Eclipse. Since I had done this in the past, I had to:

  1. Delete the Buildship update site
  2. Re-add the current update site. (Thanks to this post for the suggestion)
  3. Update plugin
  4. Restart Eclipse

That “helped” in that I got a different error:

Caused by: org.gradle.internal.exceptions.LocationAwareException: Unable to make protected void java.net.URLClassLoader.addURL(java.net.URL) accessible: module java.base does not “opens java.net” to unnamed module @6740e13b

This time it created the project on disk and merely didn’t import it. Importing had the same problem though. There is at least one known error with Java 9 and Buildship. And I’m getting a Java 9 error so clearly, I still have something pointing to Java 9 on system.

What actually worked

Running java -version showed I had Java 9 as my system default. This is because Mac defaults to the latest version. I didn’t have a problem earlier because Eclipse itself was set to use Java 8. (except when I’m playing with Java 9.)

I actually had to disable Java 9 on the Mac so it would recognize Java 8 as the default. This post shares how:

  1. cd /Library/Java/JavaVirtualMachines
  2. cd into my Java 9 directory
  3. cd contents
  4. mv Info.plist Info.plist.disabled
  5. Restart Eclipse

And a quick review of Gradle/Buildship

  1. You can intersperse running command line gradle commands and using Buildship. Since everything is stored in the gradle directories, they remember state from each other.
  2. To run “gradle clean” or “gradle build” in Buildship the first time:
    1. Go to the Gradle Tasks view
    2. Expand project
    3. Expand build
    4. Right click clean (or build)
    5. The Gradle Executions view shows what is still running
    6. The Console view shows the command line output
  3. To run “gradle clean” or “gradle build” in BuildShip the second time:
    1. Buildship automatically creates a run configuration for any builds you run. They have clear names (ex: atlanta-tourism – clean”) so you can easily find the right one. You can sticky common ones to the top since they are normal Eclipse run configurations
  4. To delete the whole gradle cache: rm /Users/xxx/.gradle/caches
  5. To delete a specific artifact rm /Users/nyjeanne/.gradle/caches/modules-2/files-2.1/… (I forgot to include a dependency and seeing everything re-downloaded helped)