- •Credits
- •About the Authors
- •About the Reviewers
- •www.PacktPub.com
- •Table of Contents
- •Preface
- •Introduction
- •Installing Groovy on Windows
- •Installing Groovy on Linux and OS X
- •Executing Groovy code from the command line
- •Using Groovy as a command-line text file editor
- •Running Groovy with invokedynamic support
- •Building Groovy from source
- •Managing multiple Groovy installations on Linux
- •Using groovysh to try out Groovy commands
- •Starting groovyConsole to execute Groovy snippets
- •Configuring Groovy in Eclipse
- •Configuring Groovy in IntelliJ IDEA
- •Introduction
- •Using Java classes from Groovy
- •Embedding Groovy into Java
- •Compiling Groovy code
- •Generating documentation for Groovy code
- •Introduction
- •Searching strings with regular expressions
- •Writing less verbose Java Beans with Groovy Beans
- •Inheriting constructors in Groovy classes
- •Defining code as data in Groovy
- •Defining data structures as code in Groovy
- •Implementing multiple inheritance in Groovy
- •Defining type-checking rules for dynamic code
- •Adding automatic logging to Groovy classes
- •Introduction
- •Reading from a file
- •Reading a text file line by line
- •Processing every word in a text file
- •Writing to a file
- •Replacing tabs with spaces in a text file
- •Deleting a file or directory
- •Walking through a directory recursively
- •Searching for files
- •Changing file attributes on Windows
- •Reading data from a ZIP file
- •Reading an Excel file
- •Extracting data from a PDF
- •Introduction
- •Reading XML using XmlSlurper
- •Reading XML using XmlParser
- •Reading XML content with namespaces
- •Searching in XML with GPath
- •Searching in XML with XPath
- •Constructing XML content
- •Modifying XML content
- •Sorting XML nodes
- •Serializing Groovy Beans to XML
- •Introduction
- •Parsing JSON messages with JsonSlurper
- •Constructing JSON messages with JsonBuilder
- •Modifying JSON messages
- •Validating JSON messages
- •Converting JSON message to XML
- •Converting JSON message to Groovy Bean
- •Using JSON to configure your scripts
- •Introduction
- •Creating a database table
- •Connecting to an SQL database
- •Modifying data in an SQL database
- •Calling a stored procedure
- •Reading BLOB/CLOB from a database
- •Building a simple ORM framework
- •Using Groovy to access Redis
- •Using Groovy to access MongoDB
- •Using Groovy to access Apache Cassandra
- •Introduction
- •Downloading content from the Internet
- •Executing an HTTP GET request
- •Executing an HTTP POST request
- •Constructing and modifying complex URLs
- •Issuing a REST request and parsing a response
- •Issuing a SOAP request and parsing a response
- •Consuming RSS and Atom feeds
- •Using basic authentication for web service security
- •Using OAuth for web service security
- •Introduction
- •Querying methods and properties
- •Dynamically extending classes with new methods
- •Overriding methods dynamically
- •Adding performance logging to methods
- •Adding transparent imports to a script
- •DSL for executing commands over SSH
- •DSL for generating reports from logfiles
- •Introduction
- •Processing collections concurrently
- •Downloading files concurrently
- •Splitting a large task into smaller parallel jobs
- •Running tasks in parallel and asynchronously
- •Using actors to build message-based concurrency
- •Using STM to atomically update fields
- •Using dataflow variables for lazy evaluation
- •Index
Chapter 6
3.The next step is to save the modified message. There is the groovy.json. JsonOutput class, which is designed specifically for that purpose. By using the static toJson and prettyPrint methods we can get an indented text version of the modified message:
println JsonOutput.prettyPrint(JsonOutput.toJson(ui))
4.Our initial modifications will lead to the following output:
{
"items": [
{
"title": "Main Window", "animate": true, "height": 270, "width": 319, "insetPadding": 20, "type": "panel"
}
]
}
How it works...
As we are operating on a Map, the code above does not do anything else but adding and removing Map entries.
The toJson method returns a String with a compact version of the JSON data. The prettyPrint method adds additional indentation spaces to any given JSON string.
See also
ff Parsing JSON messages with JsonSlurper
ff http://groovy.codehaus.org/gapi/groovy/json/JsonSlurper.html
ff http://groovy.codehaus.org/gapi/groovy/json/JsonOutput.html
Validating JSON messages
JSON is replacing XML for many applications, but one of the features that XML is exceptionally good for is the ability to validate XML content against a DTD or an XML Schema.
205
www.it-ebooks.info
Working with JSON in Groovy
Due to the lightweight nature of JSON, it is quite simple to construct invalid or incomplete messages. That's why the necessity of JSON validation will arise quite soon if you plan to develop high-quality and error-free applications.
This recipe will list some ways to validate your JSON input with the help of Groovy.
Getting ready
For this recipe, we are going to use a simple JSON document representing a vehicle and some of its core attributes. Let's define a vehicle.json file containing a JSON representation of a car:
{
"brand": "Mazda", "model": "5", "fuel": "PETROL", "releaseYear": 2007, "transmission": {
"gears": "5", "type": "MANUAL"
}
}
How to do it...
Since JSON messages are represented by Maps and Lists, you can just use the Groovy operators and collection methods—or simple GPath expressions—to navigate and express the validation rules over a parsed JSON message. More information about GPath can be found in the Searching in XML with GPath recipe in Chapter 5, Working with XML in Groovy.
1.We begin by parsing our document in the same way we did it in previous recipes (for example, Parsing JSON messages with JsonSlurper):
import groovy.json.*
def reader = new FileReader('vehicle.json') def vehicle = new JsonSlurper().parse(reader)
2.Now we can define the following validation functions in our script:
def isValidTransmission(vehicle) { vehicle?.transmission?.type in
[ 'MANUAL', 'AUTOMATIC' ] && vehicle?.transmission?.gears > 3
}
206
www.it-ebooks.info
Chapter 6
def isValidFuel(vehicle) { vehicle?.fuel in
[ 'DIESEL', 'PETROL', 'GAS', 'ELECTRIC']
}
def hasWheels(vehicle) { vehicle?.wheels?.size() > 0
}
3.Calling the validation methods as:
println 'Vehicle has valid transmission data: ' + isValidTransmission(vehicle)
println 'Vehicle |
has valid fuel: |
' + |
isValidFuel(vehicle) |
|
|
println 'Vehicle |
has wheels: |
' + |
hasWheels(vehicle)
4. The previous script yields the following output:
Vehicle has valid transmission data: true
Vehicle |
has |
valid fuel: |
true |
Vehicle |
has |
wheels: |
false |
How it works...
The previous code makes use of several very useful Groovy operators, which make Boolean expressions look very short.
One of them is the safe navigation operator ?., which stops evaluating the Boolean expression and returns null immediately if left operand is null. That means no ugly nested if statements and no unexpected NullPointerExceptions, because the expression is not evaluated further and because null will yield false in Boolean context.
So, for example, vehicle?.transmission?.gears > 3 will return false if vehicle or transmission are null, or if transmission is not null, but there are no gears and so on.
207
www.it-ebooks.info
Working with JSON in Groovy
There's more...
Another approach would be to use JSON Schema. It is an emerging standard that is created by the JSON community and it is essentially targeted to offer a similar functionality to what XML Schema provides for XML.
JSON Schema, in the same fashion as XML Schema, can be expressed in JSON itself. To give you an idea of how it looks, for our vehicle data we can define the following schema in a file:
{
"$schema": "http://json-schema.org/draft-03/schema#", "description" : "Vehicle data schema",
"type" : "object", "properties" : {
"brand" : {
"type" : "string", "required" : true
},
"model" : {
"type" : "string", "required" : true
},
"fuel" : {
"type" : "string",
"enum" : ["DIESEL", "PETROL", "GAS", "ELECTRIC"]
},
"releaseYear" : { "type" : "integer"
},
"transmission" : { "type" : "object",
"properties" : { "gears": {
"type" : "integer"
}, "type": {
"type" : "string",
"enum" : ["MANUAL", "AUTOMATIC"]
}
}
}
}
}
208
www.it-ebooks.info
Chapter 6
Basically, a JSON Schema defines a JSON object structure with the help of standard property names and conventions, for example, the type attribute defines the type (for example, String, integer, date, object, array, and so on) of the structure appearing on the same level in JSON message, properties attribute contains a collection of nested property definitions, which also describe type, name and restrictions like enum or required of the property value.
Please note that the JSON Schema is still a moving target: the example above uses the slightly older draft 3 format. A newer version, named draft 4, is available.
Currently there aren't many implementations of the JSON Schema in Java/Groovy. For this example, we are going to use an implementation called json-schema-validator.
@Grab('com.github.fge:json-schema-validator:2.0.1') import com.github.fge.jsonschema.main.JsonSchemaFactory import com.github.fge.jsonschema.report.ProcessingReport import com.github.fge.jsonschema.util.JsonLoader
import com.github.fge.jsonschema.main.JsonSchema
def factory = JsonSchemaFactory.byDefault()
def schemaFile = new File('vehicle_schema.json') def metadata = JsonLoader.fromFile(schemaFile)
def data = JsonLoader.fromFile(new File('vehicle.json'))
def schema = factory.getJsonSchema(metadata)
def report = schema.validate(data)
def success = report.isSuccess()
println("Validation ${success ? 'succeeded' : 'failed'}")
if (!success) {
println('---- BEGIN REPORT ----') report.each { message -> println message } println('---- END REPORT ----')
}
First of all, we Grab-ed the dependency for json-schema-validator and imported several required classes. The json-schema-validator library internally uses the JsonNode data structure to keep the JSON data. For this reason, we need to rely on JsonLoader to load the
JSON files.
209
www.it-ebooks.info
Working with JSON in Groovy
Noticeably, data and schema are loaded in the same way. After constructing a JsonSchema object using JsonSchemaFactory, we finally can validate the data. The last code lines just call the validation routine and print out validation messages, if any.
The script reports one error (the following output is formatted for readability):
Validation failed
----BEGIN REPORT ----
{
level="error",
schema={
"loadingURI":"#",
"pointer":"/properties/transmission/properties/gears"
},
instance={"pointer":"/transmission/gears"},
domain="validation",
keyword="type",
message="instance type does not match any allowed primitive type",
expected=["integer"],
found="string"
}
----END REPORT ----
The error reported by the validator is related to /transmission/gears: the JSON validation code expects an Integer, but the JSON document provides a String:
{
...
"transmission": { "gears": "5", "type": "MANUAL"
}
...
}
JSON Schema provides a more generic approach to validation error handling compared to the custom Groovy code.
210
www.it-ebooks.info