Need help with your JSON?
Try our JSON Formatter tool to automatically identify and fix syntax errors in your JSON. JSON Formatter tool
Groovy JSON Handling in Gradle Scripts
Gradle, a powerful and flexible build automation tool, uses Groovy or Kotlin DSL for writing build scripts. When working with complex build configurations, external data, or task inputs/outputs, you might encounter the need to handle JSON data directly within your build.gradle
files. Groovy's excellent support for JSON makes this relatively straightforward.
Why Handle JSON in Gradle?
There are several scenarios where processing JSON within your Gradle script can be beneficial:
- Configuration Management: Reading build settings, versions, or credentials from a JSON config file.
- Task Inputs/Outputs: Parsing a JSON report generated by another tool or generating a JSON file as a task output.
- External Data Integration: Processing data fetched from an external source or API (though typically this might happen in a separate script or plugin called by Gradle).
- Dynamic Task Configuration: Using data from a JSON structure to dynamically define tasks, dependencies, or properties.
Groovy's Built-in JSON Capabilities
Groovy provides excellent support for JSON parsing and generation through thegroovy.json
package. The two main classes you'll interact with are:
JsonSlurper
: For parsing JSON strings or streams into Groovy data structures (Lists, Maps, etc.).JsonOutput
: For generating JSON strings from Groovy data structures.
These classes are usually available in the Gradle Groovy environment without needing explicit dependencies in your typical build.gradle
file.
Examples in Gradle Scripts
1. Parsing JSON from a String
You can directly parse a JSON string defined within your script:
import groovy.json.JsonSlurper def jsonString = ''' { "name": "MyProject", "version": "1.0.0", "settings": { "buildDir": "dist", "minify": true }, "tags": ["gradle", "json", "example"] } ''' def jsonSlurper = new JsonSlurper() def config = jsonSlurper.parseText(jsonString) println "Project Name: ${config.name}" // Access using dot notation println "Project Version: ${config['version']}" // Access using map notation println "Build Directory: ${config.settings.buildDir}" println "First tag: ${config.tags[0]}" // You can use this data later in your build configuration gradle.ext.projectName = config.name gradle.ext.projectVersion = config.version task printConfig { doLast { println "Config from extension: ${gradle.ext.projectName} - ${gradle.ext.projectVersion}" } }
In this example, JsonSlurper().parseText()
converts the JSON string into a Groovy object which behaves like nested Maps and Lists, allowing easy access using dot notation or map-style indexing.
2. Parsing JSON from a File
Reading configuration or data from an external JSON file is a common pattern. Let's assume you have a file named config.json
in your project root:
// Example config.json content: // { // "apiUrl": "https://api.example.com/v1", // "timeout": 5000, // "features": { // "darkMode": false, // "analytics": true // } // } import groovy.json.JsonSlurper def configFile = file('config.json') if (configFile.exists()) { def jsonSlurper = new JsonSlurper() def projectConfig = jsonSlurper.parse(configFile) // Use parse() for files // Store config data in Gradle extensions for use across the build script gradle.ext.apiUrl = projectConfig.apiUrl gradle.ext.timeout = projectConfig.timeout gradle.ext.features = projectConfig.features task checkFeatures { doLast { if (gradle.ext.features.analytics) { println "Analytics feature is enabled." } else { println "Analytics feature is disabled." } println "API URL is: ${gradle.ext.apiUrl}" } } } else { println "WARNING: config.json not found. Using default settings." // Define default settings if the file is missing gradle.ext.apiUrl = "http://localhost:8080" gradle.ext.timeout = 10000 gradle.ext.features = [darkMode: false, analytics: false] }
Using jsonSlurper.parse(file)
directly handles reading the file content and parsing it. It's good practice to check if the file exists before attempting to parse it.
3. Generating JSON Output
You might need to generate a JSON file as part of a build task, for example, a report or a configuration file for another tool.
import groovy.json.JsonOutput task generateBuildInfoJson { def buildInfoFile = layout.buildDirectory.file('reports/buildInfo.json').get().asFile outputs.file buildInfoFile // Declare the output file doLast { def buildInfo = [ projectName: rootProject.name, version: version, // Project version buildTime: new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"), gradleVersion: gradle.gradleVersion, javaVersion: System.getProperty('java.version') ] // Convert Groovy map to JSON string def jsonOutputString = JsonOutput.toJson(buildInfo) // Optional: make the output pretty-printed def prettyJsonOutputString = JsonOutput.prettyPrint(jsonOutputString) // Ensure parent directories exist buildInfoFile.getParentFile().mkdirs() // Write JSON string to file buildInfoFile.text = prettyJsonOutputString println "Generated build info file: ${buildInfoFile.getAbsolutePath()}" } }
Here, we create a Groovy Map containing the build information. JsonOutput.toJson()
converts this Map into a JSON string. JsonOutput.prettyPrint()
improves readability. The task declares its output file using outputs.file
, which helps Gradle with task up-to-date checks.
4. Using JSON Data in Task Configuration
JSON data can dynamically influence how tasks behave.
import groovy.json.JsonSlurper // Assume features.json exists with content like: // { // "enabledFeatures": ["auth", "payment"], // "disabledFeatures": ["admin"] // } def featuresFile = file('features.json') def featureConfig = [enabledFeatures: [], disabledFeatures: []] // Default if (featuresFile.exists()) { try { featureConfig = new JsonSlurper().parse(featuresFile) } catch (Exception e) { println "WARNING: Failed to parse features.json: ${e.message}" // Use default config on error } } else { println "WARNING: features.json not found. Using default features." } // Example: Configure a Copy task based on enabled features task copyFeatureFiles(type: Copy) { from 'src/main/resources/features' into layout.buildDirectory.dir('features') // Include files only if the feature is enabled include { FileTreeElement details -> def fileName = details.name // Assuming file names are like 'auth.feature', 'payment.feature', 'admin.feature' def featureName = fileName.tokenize('.')[0] return featureConfig.enabledFeatures.contains(featureName) } } // Example: Configure a task property based on JSON gradle.ext.featureToggles = featureConfig.enabledFeatures.collectEntries { [(it): true] } + featureConfig.disabledFeatures.collectEntries { [(it): false] } task showFeatureToggles { doLast { println "Current Feature Toggles: ${gradle.ext.featureToggles}" } }
Here, the copyFeatureFiles
task dynamically determines which files to include based on the content of features.json
parsed during the configuration phase. We also create a map of feature toggles stored in gradle.ext
, which can be used by other tasks or plugins.
Tips and Considerations
- Configuration vs. Execution Phase: Most JSON parsing (especially for configuration) happens during Gradle's configuration phase (when the script is evaluated). If JSON processing depends on task outputs or needs to happen during task execution, wrap the logic inside
doLast
ordoFirst
blocks. Accessing files or performing actions that change state should generally be done in execution phase blocks. - Error Handling: Always consider what happens if the JSON file doesn't exist or is malformed. Use
try-catch
blocks for robustness, especially when parsing external files. Provide default values or informative warnings. - Large JSON Data: For very large JSON files, parsing them entirely into memory during the configuration phase might impact build performance. Consider processing them within a task's
doLast
block or using streaming parsers if necessary (thoughJsonSlurper
is generally efficient for typical config sizes). - Dependencies: The
groovy.json
package is typically part of the Groovy distribution bundled with Gradle. You usually don't need to add extra dependencies for basic JSON handling. - Kotlin DSL: If you are using Kotlin DSL (
build.gradle.kts
), you would use libraries like Jackson or kotlinx.serialization for JSON handling, as Groovy's built-in capabilities are not directly available in the Kotlin environment. - File Paths: Use Gradle's built-in methods like
file('path/to/file.json')
orlayout.projectDirectory.file('path/to/file.json').get().asFile
for reliable path handling.
Conclusion
Groovy provides powerful and convenient ways to handle JSON data directly within your Gradle build scripts. Whether you need to read configuration, process task inputs, or generate outputs, JsonSlurper
and JsonOutput
offer simple and effective solutions. By leveraging these capabilities, you can create more dynamic, data-driven, and flexible build processes. Remember to consider the phase of execution (configuration vs. execution) and implement robust error handling for reliable scripts.
Need help with your JSON?
Try our JSON Formatter tool to automatically identify and fix syntax errors in your JSON. JSON Formatter tool