DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
The Latest "Software Integration: The Intersection of APIs, Microservices, and Cloud-Based Systems" Trend Report
Get the report

Gradle Goodness: Validate Model In Rule Based Model Configuration

Gradle allows for rule based configuration for builds of JVM projects in Java, Groovy, Scala and more.

Hubert Klein Ikkink user avatar by
Hubert Klein Ikkink
·
Nov. 17, 16 · Tutorial
Like (4)
Save
Tweet
Share
4.54K Views

Join the DZone community and get the full member experience.

Join For Free

Rule based model configuration gives Gradle more knowledge about the objects and their dependencies. This information can be used by Gradle to optimise the build process. We define rules on how we want Gradle to create objects and how we want to mutate objects in a class that extends RuleSource. We can also add rules to validate objects available in the Gradle model space. We use the @Validate annotation on methods that have validation logic. The first argument of the method is of the type of the object we want to validate. This type must be managed by Gradle.

In the following example we use the sample from a previous post. In this sample, we have a VersionFile class that is managed by Gradle. The class has a version and outputFile property. The version must be set and must start with a v. The outputFile property is also required.

// File: buildSrc/src/main/groovy/mrhaki/gradle/VersionFileTaskRules.groovy 
package mrhaki.gradle

import org.gradle.api.GradleException import org.gradle.api.Task import org.gradle.model.Model import org.gradle.model.ModelMap import org.gradle.model.Mutate import org.gradle.model.RuleSource import org.gradle.model.Validate

class VersionFileTaskRules extends RuleSource {
    @Model
    void versionFile(final VersionFile versionFile) {
    }

    /** * Version property of {@link VersionFile} must have a value and the value 
     * must start with a 'v'. 
     * 
     * @param versionFile Gradle managed {@link VersionFile} object 
    we want to validate 
     */ 
    @Validate void validateVersionFileVersion(final VersionFile versionFile) 
    { 
        def message = 
        """\ Property VersionFile.version is not set. Set a value in the model configuration. Example: ------- model 
        { versionFile { version = 'v1.0.0' } } """.stripIndent() 
        checkAssert(message) 
        { assert versionFile.version } 
        message = """\ Property VersionFile.version should start with 'v'. 
        Set a value starting with 'v' in the model configuration. 
        Example: ------- model { versionFile { version = 'v${
        versionFile.version}' } } """.stripIndent() 
        checkAssert(message) { 
            assert versionFile.version.startsWith('v') } }

    /** 
     * Outputfile property of {@link VersionFile} must have a value. 
     * 
     * @param versionFile Gradle managed {@link VersionFile} 
    object we want to validate */ 
    @Validate void validateVersionFileOutputFile(final VersionFile versionFile) 
    { 
        def message = """\ Property VersionFile.outputFile is not set. Set a 
        value in the model configuration. Example: ------- model 
        { versionFile { outputFile = project.file("\${buildDir}/version.txt") } 
    } """.stripIndent() checkAssert(message) 
    { assert versionFile.outputFile } }

/** 
 * Run assert statement in assertion Closure. If the assertion fails 
 * we catch the exception. We use the message with the error appended with 
an user message * and throw a {@link GradleException}. 
 * 
 * @param message User message to be appended to assertion error message 
 * @param assertion Assert statement(s) to run */ 
private void checkAssert(final String message, final Closure assertion) { 
    try { 
    // Run Closure with assert statement(s). assertion() } catch (AssertionError assertionError) 
    { 
        // Use Groovy power assert output from the assertionError 
        // exception and append user message. 
        final exceptionMessage = new StringBuilder(assertionError.message) 
        exceptionMessage << System.properties['line.separator'] << 
        System.properties['line.separator'] exceptionMessage << message 
        // Throw exception so Gradle knows the validation fails.
    throw new GradleException(exceptionMessage, assertionError) }
}

@Mutate void createVersionFileTask(final ModelMap<Task> tasks, final VersionFile versionFile) 
{ 
tasks.create('generateVersionFile', VersionFileTask) 
{ task -> task.version = versionFile.version task.outputFile = versionFile.outputFile } }
}}}}

Let's use the following build file and apply the rules to the project:

// File: build.gradle 
apply plugin: mrhaki.gradle.VersionFileTaskRules model { } 

From the command line we run the model task to check the Gradle model space:

$ gradle -q model FAILURE: Build failed with an exception. 
  * What went wrong: A problem occurred configuring root project 'versionrule'. 
    > Exception thrown while executing model 
  rule: VersionFileTaskRules#validateVersionFileOutputFile(VersionFile) > 
  assert versionFile.outputFile | | | 
  null VersionFile 'versionFile' 
Property VersionFile.outputFile is not set. 
  Set a value in the model configuration. 
  Example: ------- model { versionFile 
                          { 
                            outputFile = project.file("${buildDir}/version.txt") 
                          } 
                         } 
* Try: Run with --stacktrace option to get the stack trace. 
  Run with --info or --debug option to get more log output. 
$ 

Notice the validation rules are evaluated in alphabetical order of the methods names that have the @Validate annotation.

Let's fix this and set also the version property in our build file:

// File: build.gradle 
apply plugin: mrhaki.gradle.VersionFileTaskRules model 
{ versionFile { version = '1.0.3.RELEASE' 
  outputFile = project.file("${buildDir}/version.txt") } 
} 

We rerun the model task and in the output we see the version is invalid, because it doesn't start with a v:

$ gradle -q model 
FAILURE: Build failed with an exception. 
  * What went wrong: A problem occurred configuring root project 
'versionrule'. > Exception thrown while executing model rule: 
  VersionFileTaskRules#validateVersionFileVersion(VersionFile) > 
  assert versionFile.version.startsWith('v') | | | | | false | 
  1.0.3.RELEASE VersionFile 'versionFile' 
  Property VersionFile.version should start with 'v'. 
  Set a value starting with 'v' in the model configuration. 
  Example: ------- model { versionFile { version = 'v1.0.3.RELEASE' } } 
* Try: Run with --stacktrace option to get the stack trace. 
  Run with --info or --debug option to get more log output. 
$ 

Let's make our validation pass with the following build script:

// File: build.gradle 
apply plugin: mrhaki.gradle.VersionFileTaskRules model { 
  versionFile { version = 'v1.0.3.RELEASE' 
               outputFile = project.file("${buildDir}/version.txt") } 
} 

And in the output of the model we see the properties are set with our values:

$ gradle -q model
...
+ versionFile
      | Type:           mrhaki.gradle.VersionFile
      | Creator:        VersionFileTaskRules#versionFile(VersionFile)
      | Rules:
         ⤷ versionFile { ... } @ build.gradle line 10, column 5
         ⤷ VersionFileTaskRules#validateVersionFileOutputFile(VersionFile)
         ⤷ VersionFileTaskRules#validateVersionFileVersion(VersionFile)
    + outputFile
          | Type:       java.io.File
          | Value:      /Users/mrhaki/Projects/mrhaki.com/blog/posts/samples/gradle/versionrule/build/version.txt
          | Creator:    VersionFileTaskRules#versionFile(VersionFile)
    + version
          | Type:       java.lang.String
          | Value:      v1.0.3.RELEASE
          | Creator:    VersionFileTaskRules#versionFile(VersionFile)
...
$


Gradle

Published at DZone with permission of Hubert Klein Ikkink, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Full Lifecycle API Management Is Dead
  • Application Architecture Design Principles
  • NoSQL vs SQL: What, Where, and How
  • Spring Boot, Quarkus, or Micronaut?

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: