Language Enhancements in ColdFusion Splendor – Promoting built-in CF function to first class

A while ago I started a series of blog posts on Language Enhancements in ColdFusion Splendor and today, taking it forward, I am going to write about built-in ColdFusion functions being promoted to first class objects.

A first class object is the one which could be passed as an argument to a function call, assigned to a variable or returned as a result of a function invocation. So by promoting built-in functions to first class objects, you will be able to treat ColdFusion functions (structInsert, arrayLen, listFind) as objects and hence you can:

  • Pass them as arguments to a function call
  • Assign them to variables 
  • Return them as a result of a function invocation

Here is a very simple example showing how you can pass built-in functions as an argument:

 <cfscript>
	function convertCaseForArray(Array array, function convertor)
	{
		for (var i=1; i <= arrayLen(array); i++){
        	array[i] = convertor(array[i]);
                }
		return array;
	}
       
     // lcase built-in function is being passed as callback.
	resultantArray = convertCaseForArray(['One', 'Two','Three'],  lcase);	
	writedump(resultantArray);
</cfscript>

In the above example, lcase built-in function is directly being passed as an argument to convertCaseForArray, which was not allowed till ColdFusion10. Now, let’s see an example where the lcase and ucase built-in functions are being returned from the getConvertFunc function based on the type:

<cfscript>
	function convertCaseArray(Array array, String caseTo)
	{
		caseConvertFunc = getConvertFunc(caseTo);
		for (var i=1; i <= arrayLen(array); i++){
        	array[i] = caseConvertFunc(array[i]);
    	}
		return array;
	}
	
	function getConvertFunc(String caseType)
	{
	  if(caseType == 'lower')
	  	return lcase;
	   else
                return ucase;
	}
	
	resultantArray_lower = convertCaseArray(['One', 'Two','Three'], "lower");
	resultantArray_upper = convertCaseArray(['One', 'Two','Three'], "upper");
	
	writedump(resultantArray_lower);
	writedump(resultantArray_upper);

</cfscript>


In the above example, getConvertFunc returns the convertor for the right case. 

Stay tuned for more posts on language enhancements!

Language Enhancements in ColdFusion Splendor – Elvis operator

The Elvis operator (?:) is a small but elegant feature added in Splendor. I am going to show you how it shortens your conditional code and  makes it look simpler. But before I get into the details, here is the list of language features added in ColdFusion Splendor.

The Elvis operator assigns the ‘right default’ for a variable or an expression. In an expression, if the resultant value is not defined, then the object will be assigned to the left most part of the expression otherwise a default value (define at the right most part) will be assigned.
Consider a conditional case where the displayname is populated with username variable, if the later is defined otherwise a default value “anonymous” needs to be assigned to the displayname variable. The code snippet shown below display both the syntaxes: one with Elvis operator and other without it:
 
Without Elvis
<cfscript>
   if(isdefined('username')){
       displayName = username;
   }
   else {
    displayName = "anonymous";
   }
</cfscript>

With Elvis operator

   displayName = username ?: "anonymous";

The support for Elvis operator has been provided for function calls and expressions too. Some of the expression cases are: 

 securityNumber = securityStruct[‘Joe’] ?: -1;  // Retrieving from a struct
 colourCode = colourArray[index] ?: "black";   // Retrieving from an array
 employeeName = getEmployeeName(ID) ?: “Joe”;  // A function call

Language Enhancements in ColdFusion Splendor – CF Functions for Query tag

Continuing the blog posts series on language enhancements, today, I am going to cover the Query functions and explain its various overloaded methods in detail. Before I discuss this feature, here is the list of language features added in ColdFusion Splendor.

Script syntax for Query tag is available in Splendor through the generic “Script support for tags“. This generic solution works well for all the other tags except CFQuery. CFQuery, being a bit complex, necessitated a need to provide an easy to use script-syntax for query execution. So, to simplify it in a script block, the query functions have been added in Splendor. These are designed in-line with existing ORM execute functions. The general syntax of query functions are:
QueryExecute(sql_statement);
QueryExecute(sql_statement, queryParams);
QueryExecute(sql_statement, queryParams, queryOptions);


As shown above, query functions can be invoked by passing one, two, or three parameters. The first parameter, an SQL statement is mandatory and the other two (queryParams and queryOptions) are optional. 

Query params:

There are two different ways to pass a parameter to an SQL query: named and positional (unnamed). In named parameter, you use “:” as the placeholder and pass a struct to queryParam. For the positional one, “?” is used as the placeholder and the values of the parameters are passed as an array to queryParams. 

  //named parameter 
  QueryExecute("select * from Employee where country=:country and artistid=:id", {country='USA', id:1});
  
  // positional parameter
  QueryExecute("select * from Employee where country=:? and artistid=?", ['USA', 1]);

If required, the CFQueryParam attributes information can also be passed for executing a query. For this, the attributes of an individual queryParam are first defined in a struct and then this struct is passed, rather passing  a simple string or number, as a  value of that param. To understand it better, an example is shown below:

//queryparams with attributes
QueryExecute("select * from Employee where country=:country and empId=id, {id:101, country:{name="USA", CFSQLType='CF_SQL_CLOB', list=true }});

QueryOptions

QueryOptions is a struct which contains different attribute values of a Query tag. In the following example, a “datasource” attribute has been passed in the queryOptions parameter. Similarly, all the attributes (except name) can be passed to queryOptions before executing a query.

 QueryExecute("select * from Artists where artistid=:id", {id:1},{datasource= "cfartgallery"});


This feature has been covered in details in Splendor document. See the doc for more information.

Language Enhancements in ColdFusion Splendor – Improved JSON serialization 2

In the previous post, I blogged about JSON serialization enhancements and covered a couple of
features around it. This post, a continuation from the last one, will cover the remaining features added in ColdFusion Splendor to serialize a ColdFusion object better. Before going into the details of the remaining improvements, here is the complete list of JSON features.

  • Data type preservation for Query and CFC 
  • Case preservation of struct keys
  • Added “Struct” as new QueryFormat
  • Custom serializer

Added “Struct” as new QueryFormat

In ColdFusion, Row and column are the supported types to serialize a query object. However, none of these two formats are fit for the jQuery type JavaScript framework. These JavaScript frameworks work well with column-value (like struct) format and to facilitate easy integration with these frameworks, a new query format “struct” has been introduced in ColdFusion Splendor. So, starting from Splendor, 3 different format types rowcolumn, and struct are now supported to serialize a query object to a JSON string. For example, to serialize a query object with 3 rows and 2 columns (colour,id), the serialized JSON string for row and struct query format will look like:

row  format:   {“ROWCOUNT”:3, “COLUMNS”:[“COLOUR”, “ID”], DATA:{“colour”: [“red”, “green”, “blue”], “id”: [1,2,3]}}

struct format:  [{“colour”:”red”, “id”:1}, {“colour”:”green”, “id”:2}, {“colour”:”blue”, “id”:3}]

As you can notice, the struct format is based on the key-value pair and is quite simple. The only downside of this format is the repetition of the column names. Here, the column names are repeated for each and every row.

Custom serializer

ColdFusion Splendor has enhanced JSON serialization support to help you hook your own custom serializer for serializing a ColdFusion object. The custom serializer enables you to register your own handler for serializing and deserializing the complex object. If the serializer is not specified, ColdFusion will use the in-built serialization handler.

Steps to use the custom serializer: There are two steps involved to hook a custom serializer in ColdFusion.

 1. Implement the custom serializer:  The customSerializer handler, a CFC, has four functions for you to implement.

  1. canSerialize
  2. serialize
  3. canDeserialize
  4. deserialize
 2. Register the handler:  Handler needs to be registered by adding its entry to application.cfc as following:
Application.cfc
<cfset this.customSerializer="MyCustomSerializer" />

This custom serializer has been explained in great details in ColdFusion Documentation

 

Language Enhancements in ColdFusion Splendor – Improved JSON serialization

I started a series of blog posts on language enhancements and so far covered Script support for tags and Member functions. Today, I will be blogging about the new features added in ColdFusion Splendor to improve JSON serialization.
Before I dive into the details of JSON serialization enhancements, here is the
list of the language features:

JSON serialization was first introduced in ColdFusion 8 and we constantly worked on improving this feature continously over the past several ColdFusion versions.

The complete list of JSON-level enhancements added to ColdFusion Splendor are:

  1. Data type preservation for Query and CFC 
  2. Case preservation of struct keys
  3. Added “Struct” as new QueryFormat
  4. Custom serializer
Data type preservation for Query and CFC
It has always been a challenge to rightly identify the underlying data type of a CFC property or of a column data of a query object. Prior to Splendor, ColdFusion used to check whether a data type can be converted to a number or boolean. If it can be converted, ColdFusion will automatically convert the property value to number/boolean irrespective of whether the property values needs conversion. Starting from Splendor, the metadata of the query, retrieved from the underlying database, will be used to identify the right data type of a column and the column data will be serialized based on that. Similarly, for a CFC, the CFC metadata will be retrieved and used to detect the right data type of the CFC property to serialize into.
Entity.cfc
 <cfcomponent persistent="true" table="partners" ... >
     <cfproperty name='zipcode' type="string" />
</cfcomponent>
index.cfm
   <cfscript>
        t = createObject("component", "Entity");
        t.setData("01003");
        writeoutput(serializeJSON(t));
   </cfscript>  


CF10 output      : {“zipcode”: 1003}
Splendor output : {“zipcode”: “01003”}

In the above example, unlike in ColdFusion10, the zipcode value is serialized as a string  and not as a number. Though the value looks like a numeric one, it will not be serialized as a number rather the data type information is retrieved from the underlying CFC metadata and  will be used to serialize it. 

Case preservation of struct keys

Prior to Splendor, ColdFusion did not preserve the case of a struct key but it converted it to the uppercase. Starting from Splendor, ColdFusion will preserve the original case of the struct key in which it is defined. But in case if you want to go back to the old ColdFusion behavior, you can use either the application setting or ColdFusion Administrator setting to switch back to the old behavior.  The following code will help you understand how this behavior works in ColdFusion10 and now:

<cfscript>
   data = {};
   data.empName ="John";
   data.age = 21;
   writeoutput(serialize(data));
</cfscript> 

Output in ColdFusion10   : {‘EMPNAME’= ‘John’, ‘AGE’=21}
Output in Splendor          :  {’empName ‘= ‘John’, ‘age’=21}

To keep this post short, I will be blogging the remaining JSON features in a separate post. Please refer the ColdFusion Splender public beta documentation for more details on JSON enhancement.   


Language Enhancements in ColdFusion Splendor – Member functions

Download the public beta of ColdFusion Splendor from here

I started a series of blog posts on language enhancements and covered “Script support for tags last week. Continuing on this, today I am going to blog about “Member function” that I hope should interest most of you. Before I get into the details of member functions, here is the list of language features:   

  • Script support for tags
  • Member functions for CF data type/data structure
  • Improved JSON serialization
  • Easy to use CF functions for Query tag
  • Elvis operator (?:)
  • Promoting built-in CF function to first class 
  • Miscellaneous new functions: QueryGetRow, ListEach and others. 
ColdFusion predates object-oriented programming (OOPs) and hence did not have support for OOPs syntax. If you had to perform an action on an array, a struct or say on any other CF datatype, you had to call the headless functions like “ArrayAppend” or “StructFind” prior to Splendor. Now, with addition of “Member functions” support in Splendor, you can now enjoy writing your code in true object oriented-style and can call find() method on a struct object. For instance, empStruct.find(“empID”). The code snippet shown below will help you visualize these two different coding styles:


Headless function

<cfscript>
     ArrayAppend(empArray, newObject);
     StructIsEmpty(empStruct);
</cfscript>

As member function of array/Struct

<cfscript> 
     empArray.append(newObject);
     empStruct.isEmpty();
</cfscript>

The Member function support in Splendor is quite exhaustive and covers most of the data types present in ColdFusion. The complete list of data types supported are:

  1. String
  2. List
  3. Array
  4. Struct
  5. Date
  6. Image
  7. Query
  8. SpreadSheet
  9. XML
Member function supported under each data type has been listed in ColdFusion Splender public beta documentation. Please see the documentation for more details.
Stay tuned for more on language enhancements in Splendor..  

Language Enhancements in ColdFusion Splendor

Download the public beta of ColdFusion Splendor from here

Various
enhancements have been added to the core CFML language to provide a better
development experience. Script support for CF
tags and member functions for CF data structure were long pending feature requests and we are
happy to add these two along with a few more enhancements in ColdFusion Splendor (codename). The following list shows the enhancements made in the CFML language:

  • Script support for tags
  • Member functions for CF data type/data structure
  • Improved JSON serialization
  • Easy to use CF functions for Query tag
  • Elvis operator (?:)
  • Promoting built-in CF function to first class 
  • Miscellaneous new functions: QueryGetRow, ListEach and others. 
We will be doing a series of blog posts on language enhancements and this post will only be on the Script support for tags. 

Script
support for tags
Traditionally, while coding in script syntax, you have to switch to tag-based syntax if you have to use CF tags. The reason being, the CF tags, barring
few, were not available in the script syntax.
 ColdFusion Splendor onwards, most of the ColdFusion tags are made available to be used in the CFScript block. Now, you 
can  invoke most of the CF tags within the CFScript blocks. One more good thing about the current implementation is that it will automatically take care of any future tag being added to the CF language. 

Case 1: Simple tag with no child/body.

  <cfscript>
   cfpdf (action=”getInfo”,  name=”pdfVar”,  source=”CF10MigrationGuide.pdf”);
  </cfscript>  

Note: The tag attributes should be enclosed within the parenthesis and must be comma-separated.

Case 2: Tags with child tags/body.

  <cfscript>
    cfform (name='myForm', acton='')
    {
         cfgrid (name="myGrid", query='empQuery')
        {
             cfgridcolumn (name='firstName', id='firstName', type='string');
             cfgridcolumn (name='lastName', id='LastName', type='string');
        }  
    }
  </cfscript>  

Note: The child tag (and the body in general) should be enclosed in curly brackets, as a function block

Case 3: Custom tag

ColdFusion provides three different ways to write custom tags as shown in the following list:

  1. cfmodule based custom tags (supported in Splendor)
  2. cfm file based custom tags (supported in Splendor)
  3. Prefix based custom tags (not supported)
    // Tag based syntax
    <cf_happybirthday name="John" birthDate="December 5, 1987">
    
     //Script based syntax.
     <cfscript>     
         cf_happybirthday(name="John", birthDate="December 5, 1987");
     </cfscript>  

Stay tuned for more on the language enhancements. Please refer to the ColdFusion Splender public beta documentation for more details.

JSON backward Compatibility: Flag to enable CF8 behavior

JSON serialization was
introduced in CF8 for the first time. It was used heavily to serialize CFC and
other CF data objects. In “CumulativeHotfix1 for ColdFusion 9.0.1”, some of its
outstanding issues were fixed. 
Few of issues addressed in hotfix were that of string to number
conversion, and number getting converted to double.

The change in behavior
of JSON serialization, which fixed some of the basic problems of CF developer
at one hand, also had a side effect of breaking old application built on CF8.
Migration from CF8 to later version might require making few changes in the developer’s
code.

To achieve backward
compatibility and to address a scenario where old behavior of JSON
serialization has to be retained, a JVM flag had been introduced at the same
time. If enabled, it would bypass the latest changes for JSON serialization and
fall back to CF8 behavior.

Here I am describing the JVM flag and the way to
enable it. This will bring back the old behavior where a string with leading zero like ‘000’ will be output as 0.0 rather than 000, an invalid number in javascript. Similarly all the number will be retained in double/float format. A number like 1.23E4 will be converted to 12340 and so on. So you can make use of this flag if you have got stuck upgrading to latest CF server.

To achieve the CF8 behavior, one can add a
JVM system property 
json.numberasdouble=true to jvm.config.
It is applicable to  CF “CumulativeHotfix1 for ColdFusion 9.0.1” and
later .

jvm.config file is located at  $CF_HOME/cfusion/bin/jvm.config.
Open the file and you will find “-Djava.awt.headless=true” as one of the entry
in java.args parameters.

Please add the suggested
flag just after former headless entry as  –Djson.numberasdouble=true.