Select Page

Pretty-Printing JSON Using GSON In Lucee CFML 5.3.9.141

Cyberdime
Published: July 26, 2022

I’m currently working on a proof-of-concept (POC) for a feature flag system in Lucee CFML. And, for my POC data persistence layer, I’ve been using a simple, flat JSON (JavaScript Object Notation) text file. This works great; but, I found myself wishing that the JSON file was pretty-printed so that I could more easily debug my data persistence algorithms. ColdFusion’s native serializeJson() function doesn’t have a pretty-print feature; but, I was able to use Google’s GSON library to generate pretty-printed JSON output in Lucee CFML 5.3.9.141.

One of the most exciting features of Lucee CFML is the fact that we can dynamically load JAR files with the createObject() function. Which means, in order to get GSON to work in ColdFusion, all I had to do was download the latest copy from Maven, and then provide the one JAR file in my createObject() call:

<cfscript>
	/**
	* I build the configured GSON object.
	*/
	public any function buildGson() {
		// JAR files downloaded form Maven Repository.
		var jarPaths = [
			// https://mvnrepository.com/artifact/com.google.code.gson/gson/2.9.0
			expandPath( "./vendor/gson-2.9.0/gson-2.9.0.jar")
		];
		// Normally, JSON is output as a single line, which is what makes other formats
		// like NDJSON (Newline-Delimited JSON) possible. But, for debugging purposes, it
		// is sometimes nice to see JSON rendered in a multi-line, human-friendly format.
		// That's what .setPrettyPrinting() is doing here - turning on the human-friendly
		// output formatting during the serialization process.
		var gson = createObject( "java", "com.google.gson.GsonBuilder", jarPaths )
			.init()
			.setPrettyPrinting()
			.create()
		;
		return( gson );
	}
</cfscript>

By default, the GSON client generates a single line of JSON. But, by using the “builder” to construct the GSON client, we can change its behavior. In this case, I’m calling the .setPrettyPrinting() builder method to turn-on the pretty-printing functionality. This will enable pretty-printing for all future calls to the resultant GSON client – from what I can see, there’s no way to turn this feature on-or-off on per-serialization basis.

And, now that we have our GSON client, let’s try to serialize some ColdFusion data structures and examine our output:

<cfscript>
	// Build our sample data to run through the GSON serialization process.
	data = [
		name: "CAFFEINE",
		vendor: "ProLab",
		tagline: "Performance Simplified",
		count: 100,
		price: 6.79,
		strength: 200,
		activeIngredients: [
			"Caffeine",
			"Calcium"
		],
		inactiveIngredients: [
			"Stearic Acid",
			"Cellulose Gum",
			"Silica",
			"Magnesium Stearate",
			"Methylcellulose",
			"Glycerin"
		],
		allergens: [
			Yeast: false,
			Wheat: false,
			Corn: false,
			Milk: false,
			Egg: false,
			Soy: false
		],
		// CAUTION: Date objects will not serialize with the default configuration. I
		// believe that a customer serializer would need to be implemented. Personally, I
		// like to store dates as UTC-milliseconds if I'm storing them in a flat format.
		expiresAt: now().add( "y", 10 )
	];
	serializedData = buildGson()
		.toJson( data )
	;
	// ------------------------------------------------------------------------------- //
	// ------------------------------------------------------------------------------- //
	// Output the JSON using PRE so that we keep all the embedded white space provided
	// by the pretty-print configuration..
	echo( "<pre>#encodeForHtml( serializedData )#</pre>" );
	// Let's also compare the original (source) data representation to the deserialized
	// representation from our output.
	```
	<div style="display: flex ; gap: 20px ;">
		<div>
			<cfdump
				label="Source Data (Original)"
				var="#data#"
			/>
		</div>
		<div>
			<cfdump
				label="Deserialized Data (From GSON String)"
				var="#deserializeJson( serializedData )#"
			/>
		</div>
	</div>
	```
	// ------------------------------------------------------------------------------- //
	// ------------------------------------------------------------------------------- //
	/**
	* I build the configured GSON object.
	*/
	public any function buildGson() {
		// JAR files downloaded form Maven Repository.
		var jarPaths = [
			// https://mvnrepository.com/artifact/com.google.code.gson/gson/2.9.0
			expandPath( "./vendor/gson-2.9.0/gson-2.9.0.jar")
		];
		// Normally, JSON is output as a single line, which is what makes other formats
		// like NDJSON (Newline-Delimited JSON) possible. But, for debugging purposes, it
		// is sometimes nice to see JSON rendered in a multi-line, human-friendly format.
		// That's what .setPrettyPrinting() is doing here - turning on the human-friendly
		// output formatting during the serialization process.
		var gson = createObject( "java", "com.google.gson.GsonBuilder", jarPaths )
			.init()
			.setPrettyPrinting()
			.create()
		;
		return( gson );
	}
</cfscript>

Here, I’m pretty-printing the JSON to the browser using a <pre> tag so that we get to see all of the white space that the GSON client embedded in the serialized data. I’m also running the result back through ColdFusion’s deserializeJson() just for the sake of completeness. And, when we run this ColdFusion code, we get the following output:

Pretty-printed JSON output using GSON in Lucee CFML.

And, we can see the source data and deserialized data side-by-side:

The one obvious issue with using the GSON serializer in my demo is that we lose the date/time stamp, expiresAt. That said, I don’t normally serialize and store raw date values. Instead, if I needed to store them in JSON, I would call the .getTime() method on the Date object and store the underlying UTC-milliseconds. Then, during deserialization, I could construct a ColdFusion date from the UTC-milliseconds.

That said, I would likely only use GSON in POC and demo applications. As such, this limitation isn’t really a concern for me.

The native serializeJson() method is what I use in my production ColdFusion applications. But, when persisting data to a JSON file for a demo or a proof-of-concept, the GSON client seems like an easy option to enable human-readable data persistence in Lucee CFML.

Want to use code from this post?
Check out the license.

Source: www.bennadel.com