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
doLastordoFirstblocks. 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-catchblocks 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
doLastblock or using streaming parsers if necessary (thoughJsonSlurperis generally efficient for typical config sizes). - Dependencies: The
groovy.jsonpackage 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().asFilefor 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