cleanup: remove backup serializer artifacts
This commit is contained in:
@@ -1,620 +0,0 @@
|
||||
<!---
|
||||
|
||||
Copyright 2009 Nathan Mische
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
--->
|
||||
<!--- 2024-10-05 modified by msyu: date in ISO 8601 with server timezone --->
|
||||
<cfcomponent displayname="JSONUtil" output="false">
|
||||
|
||||
<cfset this.deserializeJSON = deserializeFromJSON />
|
||||
<cfset this.serializeJSON = serializeToJSON />
|
||||
|
||||
<cfset this.deserialize = deserializeFromJSON />
|
||||
<cfset this.serialize = serializeToJSON />
|
||||
|
||||
<cfset this.isLuceeRailo = structKeyExists(server, "lucee") or structKeyExists(server, "railo") />
|
||||
|
||||
<cffunction name="init" output="false">
|
||||
<cfreturn this />
|
||||
</cffunction>
|
||||
|
||||
<cffunction
|
||||
name="deserializeFromJSON"
|
||||
access="public"
|
||||
returntype="any"
|
||||
output="false"
|
||||
hint="Converts a JSON (JavaScript Object Notation) string data representation into CFML data, such as a CFML structure or array.">
|
||||
<cfargument
|
||||
name="JSONVar"
|
||||
type="string"
|
||||
required="true"
|
||||
hint="A string that contains a valid JSON construct, or variable that represents one." />
|
||||
<cfargument
|
||||
name="strictMapping"
|
||||
type="boolean"
|
||||
required="false"
|
||||
default="true"
|
||||
hint="A Boolean value that specifies whether to convert the JSON strictly, as follows:
|
||||
<ul>
|
||||
<li><code>true:</code> (Default) Convert the JSON string to ColdFusion data types that correspond directly to the JSON data types.</li>
|
||||
<li><code>false:</code> Determine if the JSON string contains representations of ColdFusion queries, and if so, convert them to queries.</li>
|
||||
</ul>" />
|
||||
|
||||
<!--- DECLARE VARIABLES --->
|
||||
<cfset var ar = ArrayNew(1) />
|
||||
<cfset var st = StructNew() />
|
||||
<cfset var dataType = "" />
|
||||
<cfset var inQuotes = false />
|
||||
<cfset var startPos = 1 />
|
||||
<cfset var nestingLevel = 0 />
|
||||
<cfset var dataSize = 0 />
|
||||
<cfset var i = 1 />
|
||||
<cfset var skipIncrement = false />
|
||||
<cfset var j = 0 />
|
||||
<cfset var char = "" />
|
||||
<cfset var dataStr = "" />
|
||||
<cfset var structVal = "" />
|
||||
<cfset var structKey = "" />
|
||||
<cfset var colonPos = "" />
|
||||
<cfset var qRows = 0 />
|
||||
<cfset var qCols = "" />
|
||||
<cfset var qCol = "" />
|
||||
<cfset var qData = "" />
|
||||
<cfset var curCharIndex = "" />
|
||||
<cfset var curChar = "" />
|
||||
<cfset var result = "" />
|
||||
<cfset var unescapeVals = "\\,\"",\/,\b,\t,\n,\f,\r" />
|
||||
<cfset var unescapeToVals = "\,"",/,#Chr(8)#,#Chr(9)#,#Chr(10)#,#Chr(12)#,#Chr(13)#" />
|
||||
<cfset var unescapeVals2 = '\,",/,b,t,n,f,r' />
|
||||
<cfset var unescapetoVals2 = '\,",/,#Chr(8)#,#Chr(9)#,#Chr(10)#,#Chr(12)#,#Chr(13)#' />
|
||||
<cfset var dJSONString = "" />
|
||||
<cfset var pos = 0 />
|
||||
|
||||
<cfset var _data = Trim(arguments.JSONVar) />
|
||||
|
||||
<!--- NUMBER --->
|
||||
<cfif IsNumeric(_data)>
|
||||
<cfreturn Val(_data) />
|
||||
|
||||
<!--- NULL --->
|
||||
<cfelseif _data EQ "null">
|
||||
<cfreturn "null" />
|
||||
|
||||
<!--- BOOLEAN --->
|
||||
<cfelseif ListFindNoCase("true,false", _data)>
|
||||
<cfreturn _data />
|
||||
|
||||
<!--- EMPTY STRING --->
|
||||
<cfelseif _data EQ "''" OR _data EQ '""'>
|
||||
<cfreturn "" />
|
||||
|
||||
<!--- STRING --->
|
||||
<cfelseif ReFind('^"[^\\"]*(?:\\.[^\\"]*)*"$', _data) EQ 1 OR ReFind("^'[^\\']*(?:\\.[^\\']*)*'$", _data) EQ 1>
|
||||
<cfset _data = mid(_data, 2, Len(_data)-2) />
|
||||
<!--- If there are any \b, \t, \n, \f, and \r, do extra processing
|
||||
(required because ReplaceList() won't work with those) --->
|
||||
<cfif Find("\b", _data) OR Find("\t", _data) OR Find("\n", _data) OR Find("\f", _data) OR Find("\r", _data)>
|
||||
<cfset curCharIndex = 0 />
|
||||
<cfset curChar = ""/>
|
||||
<cfset dJSONString = ArrayNew(1) />
|
||||
<cfloop condition="true">
|
||||
<cfset curCharIndex = curCharIndex + 1 />
|
||||
<cfif curCharIndex GT len(_data)>
|
||||
<cfbreak />
|
||||
<cfelse>
|
||||
<cfset curChar = mid(_data, curCharIndex, 1) />
|
||||
<cfif curChar EQ "\">
|
||||
<cfset curCharIndex = curCharIndex + 1 />
|
||||
<cfset curChar = mid(_data, curCharIndex,1) />
|
||||
<cfset pos = listFind(unescapeVals2, curChar) />
|
||||
<cfif pos>
|
||||
<cfset ArrayAppend(dJSONString,ListGetAt(unescapetoVals2, pos)) />
|
||||
<cfelse>
|
||||
<cfset ArrayAppend(dJSONString,"\" & curChar) />
|
||||
</cfif>
|
||||
<cfelse>
|
||||
<cfset ArrayAppend(dJSONString,curChar) />
|
||||
</cfif>
|
||||
</cfif>
|
||||
</cfloop>
|
||||
|
||||
<cfreturn ArrayToList(dJSONString,"") />
|
||||
<cfelse>
|
||||
<cfreturn ReplaceList(_data, unescapeVals, unescapeToVals) />
|
||||
</cfif>
|
||||
|
||||
<!--- ARRAY, STRUCT, OR QUERY --->
|
||||
<cfelseif ( Left(_data, 1) EQ "[" AND Right(_data, 1) EQ "]" )
|
||||
OR ( Left(_data, 1) EQ "{" AND Right(_data, 1) EQ "}" )>
|
||||
|
||||
<!--- Store the data type we're dealing with --->
|
||||
<cfif Left(_data, 1) EQ "[" AND Right(_data, 1) EQ "]">
|
||||
<cfset dataType = "array" />
|
||||
<cfelseif ReFindNoCase('^\{"ROWCOUNT":[0-9]+,"COLUMNS":\[("[^"]+",?)+\],"DATA":\{("[^"]+":\[.*\],?)+\}\}$', _data, 0) EQ 1 AND NOT arguments.strictMapping>
|
||||
<cfset dataType = "queryByColumns" />
|
||||
<cfelseif ReFindNoCase('^\{"COLUMNS":\[("[^"]+",?)+\],"DATA":\[(\[.*\],?)+\]\}$', _data, 0) EQ 1 AND NOT arguments.strictMapping>
|
||||
<cfset dataType = "query" />
|
||||
<cfelse>
|
||||
<cfset dataType = "struct" />
|
||||
</cfif>
|
||||
|
||||
<!--- Remove the brackets --->
|
||||
<cfset _data = Trim( Mid(_data, 2, Len(_data)-2) ) />
|
||||
|
||||
<!--- Deal with empty array/struct --->
|
||||
<cfif Len(_data) EQ 0>
|
||||
<cfif dataType EQ "array">
|
||||
<cfreturn ar />
|
||||
<cfelse>
|
||||
<cfreturn st />
|
||||
</cfif>
|
||||
</cfif>
|
||||
|
||||
<!--- Loop through the string characters --->
|
||||
<cfset dataSize = Len(_data) + 1 />
|
||||
<cfloop condition="#i# LTE #dataSize#">
|
||||
<cfset skipIncrement = false />
|
||||
<!--- Save current character --->
|
||||
<cfset char = Mid(_data, i, 1) />
|
||||
|
||||
<!--- If char is a quote, switch the quote status --->
|
||||
<cfif char EQ '"'>
|
||||
<cfset inQuotes = NOT inQuotes />
|
||||
<!--- If char is escape character, skip the next character --->
|
||||
<cfelseif char EQ "\" AND inQuotes>
|
||||
<cfset i = i + 2 />
|
||||
<cfset skipIncrement = true />
|
||||
<!--- If char is a comma and is not in quotes, or if end of string, deal with data --->
|
||||
<cfelseif (char EQ "," AND NOT inQuotes AND nestingLevel EQ 0) OR i EQ Len(_data)+1>
|
||||
<cfset dataStr = Mid(_data, startPos, i-startPos) />
|
||||
|
||||
<!--- If data type is array, append data to the array --->
|
||||
<cfif dataType EQ "array">
|
||||
<cfset arrayappend( ar, deserializeFromJSON(dataStr, arguments.strictMapping) ) />
|
||||
<!--- If data type is struct or query or queryByColumns... --->
|
||||
<cfelseif dataType EQ "struct" OR dataType EQ "query" OR dataType EQ "queryByColumns">
|
||||
<cfset dataStr = Mid(_data, startPos, i-startPos) />
|
||||
<cfset colonPos = Find('":', dataStr) />
|
||||
<cfif colonPos>
|
||||
<cfset colonPos = colonPos + 1 />
|
||||
<cfelse>
|
||||
<cfset colonPos = Find(":", dataStr) />
|
||||
</cfif>
|
||||
<cfset structKey = Trim( Mid(dataStr, 1, colonPos-1) ) />
|
||||
|
||||
<!--- If needed, remove quotes from keys --->
|
||||
<cfif Left(structKey, 1) EQ "'" OR Left(structKey, 1) EQ '"'>
|
||||
<cfset structKey = Mid( structKey, 2, Len(structKey)-2 ) />
|
||||
</cfif>
|
||||
|
||||
<cfset structVal = Mid( dataStr, colonPos+1, Len(dataStr)-colonPos ) />
|
||||
|
||||
<!--- If struct, add to the structure --->
|
||||
<cfif dataType EQ "struct">
|
||||
<cfset StructInsert( st, structKey, deserializeFromJSON(structVal, arguments.strictMapping) ) />
|
||||
|
||||
<!--- If query, build the query --->
|
||||
<cfelseif dataType EQ "queryByColumns">
|
||||
<cfif structKey EQ "rowcount">
|
||||
<cfset qRows = deserializeFromJSON(structVal, arguments.strictMapping) />
|
||||
<cfelseif structKey EQ "columns">
|
||||
<cfset qCols = deserializeFromJSON(structVal, arguments.strictMapping) />
|
||||
<cfset st = QueryNew(ArrayToList(qCols)) />
|
||||
<cfif qRows>
|
||||
<cfset QueryAddRow(st, qRows) />
|
||||
</cfif>
|
||||
<cfelseif structKey EQ "data">
|
||||
<cfset qData = deserializeFromJSON(structVal, arguments.strictMapping) />
|
||||
<cfset ar = StructKeyArray(qData) />
|
||||
<cfloop from="1" to="#ArrayLen(ar)#" index="j">
|
||||
<cfloop from="1" to="#st.recordcount#" index="qRows">
|
||||
<cfset qCol = ar[j] />
|
||||
<cfset QuerySetCell(st, qCol, qData[qCol][qRows], qRows) />
|
||||
</cfloop>
|
||||
</cfloop>
|
||||
</cfif>
|
||||
<cfelseif dataType EQ "query">
|
||||
<cfif structKey EQ "columns">
|
||||
<cfset qCols = deserializeFromJSON(structVal, arguments.strictMapping) />
|
||||
<cfset st = QueryNew(ArrayToList(qCols)) />
|
||||
<cfelseif structKey EQ "data">
|
||||
<cfset qData = deserializeFromJSON(structVal, arguments.strictMapping) />
|
||||
<cfloop from="1" to="#ArrayLen(qData)#" index="qRows">
|
||||
<cfset QueryAddRow(st) />
|
||||
<cfloop from="1" to="#ArrayLen(qCols)#" index="j">
|
||||
<cfset qCol = qCols[j] />
|
||||
<cfset QuerySetCell(st, qCol, qData[qRows][j], qRows) />
|
||||
</cfloop>
|
||||
</cfloop>
|
||||
</cfif>
|
||||
</cfif>
|
||||
</cfif>
|
||||
|
||||
<cfset startPos = i + 1 />
|
||||
<!--- If starting a new array or struct, add to nesting level --->
|
||||
<cfelseif "{[" CONTAINS char AND NOT inQuotes>
|
||||
<cfset nestingLevel = nestingLevel + 1 />
|
||||
<!--- If ending an array or struct, subtract from nesting level --->
|
||||
<cfelseif "]}" CONTAINS char AND NOT inQuotes>
|
||||
<cfset nestingLevel = nestingLevel - 1 />
|
||||
</cfif>
|
||||
|
||||
<cfif NOT skipIncrement>
|
||||
<cfset i = i + 1 />
|
||||
</cfif>
|
||||
</cfloop>
|
||||
|
||||
<!--- Return appropriate value based on data type --->
|
||||
<cfif dataType EQ "array">
|
||||
<cfreturn ar />
|
||||
<cfelse>
|
||||
<cfreturn st />
|
||||
</cfif>
|
||||
|
||||
<!--- INVALID JSON --->
|
||||
<cfelse>
|
||||
<cfthrow message="JSON parsing failure." />
|
||||
</cfif>
|
||||
</cffunction>
|
||||
|
||||
<cffunction
|
||||
name="serializeToJSON"
|
||||
access="public"
|
||||
returntype="string"
|
||||
output="false"
|
||||
hint="Converts ColdFusion data into a JSON (JavaScript Object Notation) representation of the data.">
|
||||
<cfargument
|
||||
name="var"
|
||||
type="any"
|
||||
required="true"
|
||||
hint="A ColdFusion data value or variable that represents one." />
|
||||
<cfargument
|
||||
name="serializeQueryByColumns"
|
||||
type="boolean"
|
||||
required="false"
|
||||
default="false"
|
||||
hint="A Boolean value that specifies how to serialize ColdFusion queries.
|
||||
<ul>
|
||||
<li><code>false</code>: (Default) Creates an object with two entries: an array of column names and an array of row arrays. This format is required by the HTML format cfgrid tag.</li>
|
||||
<li><code>true</code>: Creates an object that corresponds to WDDX query format.</li>
|
||||
</ul>">
|
||||
<cfargument
|
||||
name="strictMapping"
|
||||
type="boolean"
|
||||
required="false"
|
||||
default="false"
|
||||
hint="A Boolean value that specifies whether to convert the ColdFusion data strictly, as follows:
|
||||
<ul>
|
||||
<li><code>false:</code> (Default) Convert the ColdFusion data to a JSON string using ColdFusion data types.</li>
|
||||
<li><code>true:</code> Convert the ColdFusion data to a JSON string using underlying Java/SQL data types.</li>
|
||||
</ul>" />
|
||||
|
||||
<!--- VARIABLE DECLARATION --->
|
||||
<cfset var jsonString = "" />
|
||||
<cfset var tempVal = "" />
|
||||
<cfset var arKeys = "" />
|
||||
<cfset var colPos = 1 />
|
||||
<cfset var md = "" />
|
||||
<cfset var rowDel = "" />
|
||||
<cfset var colDel = "" />
|
||||
<cfset var className = "" />
|
||||
<cfset var i = 1 />
|
||||
<cfset var column = "" />
|
||||
<cfset var datakey = "" />
|
||||
<cfset var recordcountkey = "" />
|
||||
<cfset var columnlist = "" />
|
||||
<cfset var columnlistkey = "" />
|
||||
<cfset var columnJavaTypes = "" />
|
||||
<cfset var dJSONString = "" />
|
||||
<cfset var escapeToVals = "\\,\"",\/,\b,\t,\n,\f,\r" />
|
||||
<cfset var escapeVals = "\,"",/,#Chr(8)#,#Chr(9)#,#Chr(10)#,#Chr(12)#,#Chr(13)#" />
|
||||
|
||||
<cfset var _data = arguments.var />
|
||||
|
||||
<cfif arguments.strictMapping>
|
||||
<!--- GET THE CLASS NAME --->
|
||||
<cfset className = getClassName(_data) />
|
||||
</cfif>
|
||||
|
||||
<!--- TRY STRICT MAPPING --->
|
||||
|
||||
<cfif Len(className) AND CompareNoCase(className,"java.lang.String") eq 0>
|
||||
<cfreturn '"' & ReplaceList(_data, escapeVals, escapeToVals) & '"' />
|
||||
|
||||
<cfelseif Len(className) AND CompareNoCase(className,"java.lang.Boolean") eq 0>
|
||||
<cfreturn ReplaceList(ToString(_data), 'YES,NO', 'true,false') />
|
||||
|
||||
<cfelseif Len(className) AND CompareNoCase(className,"java.lang.Integer") eq 0>
|
||||
<cfreturn ToString(_data) />
|
||||
|
||||
<cfelseif Len(className) AND CompareNoCase(className,"java.lang.Long") eq 0>
|
||||
<cfreturn ToString(_data) />
|
||||
|
||||
<cfelseif Len(className) AND CompareNoCase(className,"java.lang.Float") eq 0>
|
||||
<cfreturn ToString(_data) />
|
||||
|
||||
<cfelseif Len(className) AND CompareNoCase(className,"java.lang.Double") eq 0>
|
||||
<cfreturn ToString(_data) />
|
||||
|
||||
<!--- BINARY --->
|
||||
<cfelseif IsBinary(_data)>
|
||||
<cfthrow message="JSON serialization failure: Unable to serialize binary data to JSON." />
|
||||
|
||||
<!--- BOOLEAN --->
|
||||
<cfelseif IsBoolean(_data) AND NOT IsNumeric(_data)>
|
||||
<cfreturn ReplaceList(YesNoFormat(_data), 'Yes,No', 'true,false') />
|
||||
|
||||
<!--- NUMBER --->
|
||||
<cfelseif IsNumeric(_data)>
|
||||
<cfif getClassName(_data) eq "java.lang.String">
|
||||
<cfreturn Val(_data).toString() />
|
||||
<cfelse>
|
||||
<cfreturn _data.toString() />
|
||||
</cfif>
|
||||
|
||||
<!--- DATE --->
|
||||
<cfelseif IsDate(_data)>
|
||||
<!--- <cfreturn '"#DateFormat(_data, "mmmm, dd yyyy")# #TimeFormat(_data, "HH:mm:ss")#"' /> --->
|
||||
<!--- // Write the date in ISO 8601 time string format. We're going to assume that the
|
||||
// date is already in the desired timezone.
|
||||
///writeOutput( """" & dateFormat( input, "yyyy-mm-dd" ) & "T" & timeFormat( input, "HH:mm:ss.l" ) & "Z""" );
|
||||
//2024-06-27 modified by msyu: added server timezone --->
|
||||
<cfreturn """" & dateFormat( _data, "yyyy-mm-dd" ) & "T" & timeFormat( _data, "HH:mm:ss.lXX" ) & """" />
|
||||
|
||||
<!--- STRING --->
|
||||
<cfelseif IsSimpleValue(_data)>
|
||||
<!---<cfreturn '"' & ReplaceList(_data, escapeVals, escapeToVals) & '"' />--->
|
||||
<cfreturn writeJsonUtf8String(_data) />
|
||||
|
||||
<!--- RAILO XML --->
|
||||
<cfelseif this.isLuceeRailo and IsXML(_data)>
|
||||
<cfreturn '"' & ReplaceList(ToString(_data), escapeVals, escapeToVals) & '"' />
|
||||
|
||||
<!--- CUSTOM FUNCTION --->
|
||||
<cfelseif IsCustomFunction(_data)>
|
||||
<cfreturn serializeToJSON( GetMetadata(_data), arguments.serializeQueryByColumns, arguments.strictMapping) />
|
||||
|
||||
<!--- OBJECT --->
|
||||
<cfelseif IsObject(_data)>
|
||||
<cfreturn "{}" />
|
||||
|
||||
<!--- ARRAY --->
|
||||
<cfelseif IsArray(_data)>
|
||||
<cfset dJSONString = ArrayNew(1) />
|
||||
<cfloop from="1" to="#ArrayLen(_data)#" index="i">
|
||||
<cfset tempVal = serializeToJSON( _data[i], arguments.serializeQueryByColumns, arguments.strictMapping ) />
|
||||
<cfset ArrayAppend(dJSONString,tempVal) />
|
||||
</cfloop>
|
||||
|
||||
<cfreturn "[" & ArrayToList(dJSONString,",") & "]" />
|
||||
|
||||
<!--- STRUCT --->
|
||||
<cfelseif IsStruct(_data)>
|
||||
<cfset dJSONString = ArrayNew(1) />
|
||||
<cfset arKeys = StructKeyArray(_data) />
|
||||
<cfloop from="1" to="#ArrayLen(arKeys)#" index="i">
|
||||
<cfif IsDefined("_data.#arKeys[i]#") >
|
||||
<cfset tempVal = serializeToJSON(_data[ arKeys[i] ], arguments.serializeQueryByColumns, arguments.strictMapping ) />
|
||||
<cfelse>
|
||||
<cfset tempVal = "null" />
|
||||
</cfif>
|
||||
<cfset ArrayAppend(dJSONString,'"' & arKeys[i] & '":' & tempVal) />
|
||||
</cfloop>
|
||||
|
||||
<cfreturn "{" & ArrayToList(dJSONString,",") & "}" />
|
||||
|
||||
<!--- QUERY --->
|
||||
<cfelseif IsQuery(_data)>
|
||||
<cfset dJSONString = ArrayNew(1) />
|
||||
|
||||
<!--- Add query meta data --->
|
||||
<cfset recordcountKey = "ROWCOUNT" />
|
||||
<cfset columnlistKey = "COLUMNS" />
|
||||
<cfset columnlist = "" />
|
||||
<cfset dataKey = "DATA" />
|
||||
<cfset md = GetMetadata(_data) />
|
||||
<cfset columnJavaTypes = StructNew() />
|
||||
<cfloop from="1" to="#ArrayLen(md)#" index="column">
|
||||
<cfset columnlist = ListAppend(columnlist,UCase(md[column].Name),',') />
|
||||
<cfif StructKeyExists(md[column],"TypeName")>
|
||||
<cfset columnJavaTypes[md[column].Name] = getJavaType(md[column].TypeName) />
|
||||
<cfelse>
|
||||
<cfset columnJavaTypes[md[column].Name] = "" />
|
||||
</cfif>
|
||||
</cfloop>
|
||||
|
||||
<cfif arguments.serializeQueryByColumns>
|
||||
<cfset ArrayAppend(dJSONString,'"#recordcountKey#":' & _data.recordcount) />
|
||||
<cfset ArrayAppend(dJSONString,',"#columnlistKey#":[' & ListQualify(columnlist, '"') & ']') />
|
||||
<cfset ArrayAppend(dJSONString,',"#dataKey#":{') />
|
||||
<cfset colDel = "">
|
||||
<cfloop list="#columnlist#" delimiters="," index="column">
|
||||
<cfset ArrayAppend(dJSONString,colDel) />
|
||||
<cfset ArrayAppend(dJSONString,'"#column#":[') />
|
||||
<cfset rowDel = "">
|
||||
<cfloop from="1" to="#_data.recordcount#" index="i">
|
||||
<cfset ArrayAppend(dJSONString,rowDel) />
|
||||
<cfif (arguments.strictMapping or this.isLuceeRailo) AND Len(columnJavaTypes[column])>
|
||||
<cfset tempVal = serializeToJSON( JavaCast(columnJavaTypes[column],_data[column][i]), arguments.serializeQueryByColumns, arguments.strictMapping ) />
|
||||
<cfelse>
|
||||
<cfset tempVal = serializeToJSON( _data[column][i], arguments.serializeQueryByColumns, arguments.strictMapping ) />
|
||||
</cfif>
|
||||
<cfset ArrayAppend(dJSONString,tempVal) />
|
||||
<cfset rowDel = ",">
|
||||
</cfloop>
|
||||
<cfset ArrayAppend(dJSONString,']') />
|
||||
<cfset colDel = ",">
|
||||
</cfloop>
|
||||
<cfset ArrayAppend(dJSONString,'}') />
|
||||
<cfelse>
|
||||
<cfset ArrayAppend(dJSONString,'"#columnlistKey#":[' & ListQualify(columnlist, '"') & ']') />
|
||||
<cfset ArrayAppend(dJSONString,',"#dataKey#":[') />
|
||||
<cfset rowDel = "">
|
||||
<cfloop from="1" to="#_data.recordcount#" index="i">
|
||||
<cfset ArrayAppend(dJSONString,rowDel) />
|
||||
<cfset ArrayAppend(dJSONString,'[') />
|
||||
<cfset colDel = "">
|
||||
<cfloop list="#columnlist#" delimiters="," index="column">
|
||||
<cfset ArrayAppend(dJSONString,colDel) />
|
||||
<cfif (arguments.strictMapping or this.isLuceeRailo) AND Len(columnJavaTypes[column])>
|
||||
<cfset tempVal = serializeToJSON( JavaCast(columnJavaTypes[column],_data[column][i]), arguments.serializeQueryByColumns, arguments.strictMapping ) />
|
||||
<cfelse>
|
||||
<cfset tempVal = serializeToJSON( _data[column][i], arguments.serializeQueryByColumns, arguments.strictMapping ) />
|
||||
</cfif>
|
||||
<cfset ArrayAppend(dJSONString,tempVal) />
|
||||
<cfset colDel=","/>
|
||||
</cfloop>
|
||||
<cfset ArrayAppend(dJSONString,']') />
|
||||
<cfset rowDel = "," />
|
||||
</cfloop>
|
||||
<cfset ArrayAppend(dJSONString,']') />
|
||||
</cfif>
|
||||
|
||||
<cfreturn "{" & ArrayToList(dJSONString,"") & "}">
|
||||
|
||||
<!--- XML --->
|
||||
<cfelseif IsXML(_data)>
|
||||
<cfreturn '"' & ReplaceList(ToString(_data), escapeVals, escapeToVals) & '"' />
|
||||
|
||||
|
||||
<!--- UNKNOWN OBJECT TYPE --->
|
||||
<cfelse>
|
||||
<cfreturn "{}" />
|
||||
</cfif>
|
||||
|
||||
</cffunction>
|
||||
|
||||
<cffunction
|
||||
name="getJavaType"
|
||||
access="private"
|
||||
returntype="string"
|
||||
output="false"
|
||||
hint="Maps SQL to Java types. Returns blank string for unhandled SQL types.">
|
||||
<cfargument
|
||||
name="sqlType"
|
||||
type="string"
|
||||
required="true"
|
||||
hint="A SQL datatype." />
|
||||
|
||||
<cfswitch expression="#arguments.sqlType#">
|
||||
|
||||
<cfcase value="bit">
|
||||
<cfreturn "boolean" />
|
||||
</cfcase>
|
||||
|
||||
<cfcase value="tinyint,smallint,integer">
|
||||
<cfreturn "int" />
|
||||
</cfcase>
|
||||
|
||||
<cfcase value="bigint">
|
||||
<cfreturn "long" />
|
||||
</cfcase>
|
||||
|
||||
<cfcase value="real,float">
|
||||
<cfreturn "float" />
|
||||
</cfcase>
|
||||
|
||||
<cfcase value="double">
|
||||
<cfreturn "double" />
|
||||
</cfcase>
|
||||
|
||||
<cfcase value="char,varchar,longvarchar">
|
||||
<cfreturn "string" />
|
||||
</cfcase>
|
||||
|
||||
<cfdefaultcase>
|
||||
<cfreturn "" />
|
||||
</cfdefaultcase>
|
||||
|
||||
</cfswitch>
|
||||
|
||||
</cffunction>
|
||||
|
||||
<cffunction
|
||||
name="getClassName"
|
||||
access="private"
|
||||
returntype="string"
|
||||
output="false"
|
||||
hint="Returns a variable's underlying java Class name.">
|
||||
<cfargument
|
||||
name="data"
|
||||
type="any"
|
||||
required="true"
|
||||
hint="A variable." />
|
||||
|
||||
<!--- GET THE CLASS NAME --->
|
||||
<cftry>
|
||||
<cfreturn arguments.data.getClass().getName() />
|
||||
<cfcatch type="any">
|
||||
<cfreturn "" />
|
||||
</cfcatch>
|
||||
</cftry>
|
||||
|
||||
</cffunction>
|
||||
|
||||
<cffunction
|
||||
name="writeJsonUtf8String"
|
||||
access="private"
|
||||
returntype="string"
|
||||
output="false"
|
||||
hint="Returns a variable's underlying java Class name.">
|
||||
<cfargument
|
||||
name="data"
|
||||
type="string"
|
||||
required="true"
|
||||
hint="A string to serialze." />
|
||||
|
||||
<!--- GET THE CLASS NAME --->
|
||||
<cfset var json = '"' />
|
||||
<cfset var end = Len(data) - 1 />
|
||||
<cfset var i = 0 />
|
||||
<cfset var c = "" />
|
||||
<cfset var integer = CreateObject("java","java.lang.Integer") />
|
||||
<cfset var pad = "" />
|
||||
<cfset var hex = "" />
|
||||
|
||||
<cfloop from="0" to="#end#" index="i">
|
||||
<cfset c = data.charAt(i) />
|
||||
<cfif c lt ' '>
|
||||
<cfif c eq Chr(8)>
|
||||
<cfset json = json & "\b" />
|
||||
<cfelseif c eq Chr(9)>
|
||||
<cfset json = json & "\t" />
|
||||
<cfelseif c eq Chr(10)>
|
||||
<cfset json = json & "\n" />
|
||||
<cfelseif c eq Chr(12)>
|
||||
<cfset json = json & "\f" />
|
||||
<cfelseif c eq Chr(13)>
|
||||
<cfset json = json & "\r" />
|
||||
<cfelse>
|
||||
<cfset hex = integer.toHexString(c) />
|
||||
<cfset json = json & "\u" />
|
||||
<cfset pad = 4 - Len(hex) />
|
||||
<cfset json = json & RepeatString("0", pad) />
|
||||
<cfset json = json & hex />
|
||||
</cfif>
|
||||
<cfelseif c eq '\' or c eq '/' or c eq '"'>
|
||||
<cfset json = json & "\" & c />
|
||||
<cfelse>
|
||||
<cfset json = json & c />
|
||||
</cfif>
|
||||
</cfloop>
|
||||
<cfset json = json & '"' />
|
||||
|
||||
<cfreturn json />
|
||||
|
||||
</cffunction>
|
||||
|
||||
</cfcomponent>
|
||||
@@ -1,19 +0,0 @@
|
||||
<cfcomponent extends="taffy.core.baseSerializer">
|
||||
|
||||
<cffunction
|
||||
name="getAsJson"
|
||||
output="false"
|
||||
taffy:mime="application/json"
|
||||
taffy:default="true">
|
||||
<cfreturn variables.jsonSerializer.serialize(variables.data) />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="setJsonSerializer" output="false">
|
||||
<cfargument name="jsonSerializer" required="true" />
|
||||
<cfset variables.jsonSerializer = arguments.jsonSerializer />
|
||||
<!--- Уже здесь непонятно, как это работает. Похоже на dependency injection?
|
||||
Почему не вызывается init? --->
|
||||
<cfset variables.jsonSerializer.init()/>
|
||||
</cffunction>
|
||||
|
||||
</cfcomponent>
|
||||
@@ -1,519 +0,0 @@
|
||||
component
|
||||
extends="taffy.core.baseSerializer"
|
||||
output = false
|
||||
hint = "I provide a way to serialize complex ColdFusion data values as case-sensitive JavaScript Object Notation (JSON) strings."
|
||||
{
|
||||
//2024-06-27 modified by msyu: added server timezone
|
||||
//2024-10-05 modified by msyu: null fix from JSONUtils (yet still no luck with case sens and date format).Вспомнил, что этому сериализатору нужно указывать тип каждого поля
|
||||
|
||||
// I return the initialized component.
|
||||
public any function init() {
|
||||
|
||||
// Every key is added to the full key list - used for one-time key serialization.
|
||||
fullKeyList = {};
|
||||
|
||||
// Every key is added to the hint list so that we don't have to switch on the lists.
|
||||
fullHintList = {};
|
||||
|
||||
// These key lists determine special data serialization.
|
||||
stringKeyList = {};
|
||||
booleanKeyList = {};
|
||||
integerKeyList = {};
|
||||
floatKeyList = {};
|
||||
dateKeyList = {};
|
||||
|
||||
// These keys will NOT be used in serialization (ie. the key/value pairs will not be
|
||||
// added to the serialized output).
|
||||
blockedKeyList = {};
|
||||
|
||||
// Return the initialized component.
|
||||
return( this );
|
||||
|
||||
}
|
||||
|
||||
|
||||
// ---
|
||||
// PUBLIC METHODS.
|
||||
// ---
|
||||
|
||||
|
||||
// I define the given key without a type. This is here to provide key-casing without caring
|
||||
// about why type of data conversion takes place. Returns serializer.
|
||||
public any function asAny( required string key ) {
|
||||
|
||||
return( defineKey( fullKeyList, key, "any" ) );
|
||||
|
||||
}
|
||||
|
||||
|
||||
// I define the given key as a boolean. Returns serializer.
|
||||
public any function asBoolean( required string key ) {
|
||||
|
||||
return( defineKey( booleanKeyList, key, "boolean" ) );
|
||||
|
||||
}
|
||||
|
||||
|
||||
// I define the given key as a date. Returns serializer.
|
||||
public any function asDate( required string key ) {
|
||||
|
||||
return( defineKey( dateKeyList, key, "date" ) );
|
||||
|
||||
}
|
||||
|
||||
|
||||
// I define the given key as a float / decimal. Returns serializer.
|
||||
public any function asFloat( required string key ) {
|
||||
|
||||
return( defineKey( floatKeyList, key, "float" ) );
|
||||
|
||||
}
|
||||
|
||||
|
||||
// I define the given key as an integer. Returns serializer.
|
||||
public any function asInteger( required string key ) {
|
||||
|
||||
return( defineKey( integerKeyList, key, "integer" ) );
|
||||
|
||||
}
|
||||
|
||||
|
||||
// I define the given key as a string. Returns serializer.
|
||||
public any function asString( required string key ) {
|
||||
|
||||
return( defineKey( stringKeyList, key, "string" ) );
|
||||
|
||||
}
|
||||
|
||||
|
||||
// I define the key as one that should not be included in the serialized response.
|
||||
public any function exclude( required string key ) {
|
||||
|
||||
blockedKeyList[ key ] = true;
|
||||
|
||||
return( this );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* I serialize the given input as JavaScript Object Notation (JSON) using the case-sensitive
|
||||
* values defined in the key-list.
|
||||
*
|
||||
* @output false
|
||||
*/
|
||||
public string function serialize( required any input ) {
|
||||
|
||||
// Write the serialized value to the output buffer.
|
||||
savecontent variable = "local.serializedInput" {
|
||||
|
||||
serializeInput( input, "any" );
|
||||
|
||||
}
|
||||
|
||||
return( serializedInput );
|
||||
|
||||
}
|
||||
|
||||
|
||||
// ---
|
||||
// PRIVATE METHODS.
|
||||
// ---
|
||||
|
||||
|
||||
// I define the given key within the given key list.
|
||||
private any function defineKey(
|
||||
required struct keyList,
|
||||
required string key,
|
||||
required string hint
|
||||
) {
|
||||
|
||||
if ( structKeyExists( fullKeyList, key ) ) {
|
||||
|
||||
throw(
|
||||
type = "DuplicateKey",
|
||||
message = "The key [#key#] has already been defined within the serializer.",
|
||||
detail = "The current key list is: #structKeyList( fullKeyList, ', ' )#"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
// Add to the appropriate data-type lists. This one is used for existence checking.
|
||||
keyList[ key ] = key;
|
||||
|
||||
// Add all keys to the full key list as well. This one is used to store the serialization
|
||||
// of the key so that it doesn't have to be recalculated each time the object is serialized.
|
||||
fullKeyList[ key ] = serializeString( key );
|
||||
|
||||
// If we have a specific type, then add the hint to the full hint list as well. This will
|
||||
// allow us to quickly look up the pass-through data type hint during serialization.
|
||||
// --
|
||||
// NOTE: The reason we don't want to pass through "any" is that we want parent types to be
|
||||
// able to "fall through" during the object traversal. If we added "any" to the type list,
|
||||
// then it would always overwrite the parent data type.
|
||||
if ( hint != "any" ) {
|
||||
|
||||
fullHintList[ key ] = hint;
|
||||
|
||||
}
|
||||
|
||||
// Return this reference for method chaining.
|
||||
return( this );
|
||||
|
||||
}
|
||||
|
||||
|
||||
// I walk the given object, writing the serialized value to the output (which is expected to
|
||||
// be a content buffer).
|
||||
// ---
|
||||
// NOTE: THIS METHOD IS HUGE - this is on purpose. Since serialization is a rather intense
|
||||
// process, I am trying to cut out as much overhead as possible. In this case, we're cutting
|
||||
// out extra stack space by inlining and duplicating a lot of functionality. This is being done
|
||||
// at the COST of clarity and non-repetitive code.
|
||||
private void function serializeInput(
|
||||
required any input,
|
||||
required string hint
|
||||
) {
|
||||
|
||||
// Serialize the data base on the type of input. We are organizing this in terms of the
|
||||
// most commonly-used values first. The anticipation is that the vast majority of data
|
||||
// types will be simple values.
|
||||
if ( isSimpleValue( input ) ) {
|
||||
|
||||
if ( ( hint == "string" ) || ( hint == "any" ) ) {
|
||||
|
||||
// If the string appears to be numeric, then we have to prefix it to make sure
|
||||
// ColdFusion doesn't accidentally convert it to a number.
|
||||
if ( isNumeric( input ) ) {
|
||||
|
||||
writeOutput( """" & input & """" );
|
||||
|
||||
} else {
|
||||
|
||||
serializeInputString( input );
|
||||
|
||||
}
|
||||
|
||||
} else if ( ( hint == "boolean" ) && isBoolean( input ) ) {
|
||||
|
||||
writeOutput( input ? "true" : "false" );
|
||||
|
||||
} else if ( ( ( hint == "integer" ) || ( hint == "float" ) ) && isNumeric( input ) ) {
|
||||
|
||||
writeOutput( input );
|
||||
|
||||
} else if ( ( ( hint == "integer" ) || ( hint == "float" ) ) && isBoolean( input ) ) {
|
||||
|
||||
writeOutput( input ? "1" : "0" );
|
||||
|
||||
} else if ( ( hint == "date" ) && ( isDate( input ) || isNumericDate( input ) ) ) {
|
||||
|
||||
// Write the date in ISO 8601 time string format. We're going to assume that the
|
||||
// date is already in the desired timezone.
|
||||
///writeOutput( """" & dateFormat( input, "yyyy-mm-dd" ) & "T" & timeFormat( input, "HH:mm:ss.l" ) & "Z""" );
|
||||
//2024-06-27 modified by msyu: added server timezone
|
||||
writeOutput( """" & dateFormat( input, "yyyy-mm-dd" ) & "T" & timeFormat( input, "HH:mm:ss.lXX" ) & """" );
|
||||
|
||||
} else {
|
||||
|
||||
serializeInputString( input );
|
||||
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
} // END: isSimpleValue().
|
||||
|
||||
|
||||
// I'm expecting the struct to be the next most common data type since it will likely be
|
||||
// the container for the majority of data values.
|
||||
if ( isStruct( input ) ) {
|
||||
|
||||
writeOutput( "{" );
|
||||
|
||||
var isFirst = true;
|
||||
|
||||
for ( var key in input ) {
|
||||
|
||||
// Skip any black-listed keys.
|
||||
if ( structKeyExists( blockedKeyList, key ) ) {
|
||||
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
// Handle the item delimiter.
|
||||
if ( isFirst ) {
|
||||
|
||||
isFirst = false;
|
||||
|
||||
} else {
|
||||
|
||||
writeOutput( "," );
|
||||
|
||||
}
|
||||
|
||||
// Ensure that the given key can be referenced on the full-key list. This way,
|
||||
// the subsequent logic will be easier.
|
||||
if ( ! structKeyExists( fullKeyList, key ) ) {
|
||||
|
||||
asAny( lcase( key ) );
|
||||
|
||||
}
|
||||
|
||||
writeOutput( fullKeyList[ key ] & ":" );
|
||||
|
||||
// Pass in the most appropriate data-type hint based on the parent key.
|
||||
if ( structKeyExists( fullHintList, key ) ) {
|
||||
|
||||
serializeInput( input[ key ], fullHintList[ key ] );
|
||||
|
||||
// If the given key is unknown, just pass through the most recent hint as
|
||||
// it may be defining the type for an entire structure.
|
||||
} else {
|
||||
// patch for null, from JSONUtils
|
||||
if (IsDefined("input.#key#")) {
|
||||
serializeInput( input[ key ], hint);
|
||||
} else {
|
||||
writeOutput("null") ;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
writeOutput( "}" );
|
||||
|
||||
return;
|
||||
|
||||
} // END: isStruct().
|
||||
|
||||
|
||||
if ( isArray( input ) ) {
|
||||
|
||||
writeOutput( "[" );
|
||||
|
||||
var isFirst = true;
|
||||
|
||||
// Handle the item delimiter.
|
||||
for ( var value in input ) {
|
||||
|
||||
if ( isFirst ) {
|
||||
|
||||
isFirst = false;
|
||||
|
||||
} else {
|
||||
|
||||
writeOutput( "," );
|
||||
|
||||
}
|
||||
|
||||
// Since we don't have a key to go off of, pass-through the most recent hint.
|
||||
serializeInput( value, hint );
|
||||
|
||||
}
|
||||
|
||||
writeOutput( "]" );
|
||||
|
||||
return;
|
||||
|
||||
} // END: isArray().
|
||||
|
||||
|
||||
// When we serialize a query, we're going to treat it like an array of structs.
|
||||
if ( isQuery( input ) ) {
|
||||
|
||||
var keys = listToArray( input.columnList );
|
||||
|
||||
// Make sure each column is defined as a known key - makes the subsequent logic easier.
|
||||
for ( var key in keys ) {
|
||||
|
||||
if ( ! structKeyExists( fullKeyList, key ) ) {
|
||||
|
||||
asAny( lcase( key ) );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
writeOutput( "[" );
|
||||
|
||||
// Serialize each row of the query as a struct.
|
||||
for ( var i = 1 ; i <= input.recordCount ; i++ ) {
|
||||
|
||||
// Handle the row delimiter.
|
||||
if ( i > 1 ) {
|
||||
|
||||
writeOutput( "," );
|
||||
|
||||
}
|
||||
|
||||
writeOutput( "{" );
|
||||
|
||||
var isFirst = true;
|
||||
|
||||
for ( var key in keys ) {
|
||||
|
||||
// Skip any black-listed keys.
|
||||
if ( structKeyExists( blockedKeyList, key ) ) {
|
||||
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
// Handle the item delimiter (in the current row).
|
||||
if ( isFirst ) {
|
||||
|
||||
isFirst = false;
|
||||
|
||||
} else {
|
||||
|
||||
writeOutput( "," );
|
||||
|
||||
}
|
||||
|
||||
writeOutput( fullKeyList[ key ] & ":" );
|
||||
|
||||
// Pass in the most appropriate data-type hint based on the parent key.
|
||||
if ( structKeyExists( fullHintList, key ) ) {
|
||||
|
||||
serializeInput( input[ key ][ i ], fullHintList[ key ] );
|
||||
|
||||
// If the given key is unknown, just pass through the most recent hint as
|
||||
// it may be defining the type for an entire structure.
|
||||
} else {
|
||||
|
||||
serializeInput( input[ key ][ i ], hint );
|
||||
|
||||
}
|
||||
|
||||
} // END: Key list.
|
||||
|
||||
writeOutput( "}" );
|
||||
|
||||
} // END: Row list.
|
||||
|
||||
writeOutput( "]" );
|
||||
|
||||
return;
|
||||
|
||||
} // END: isQuery().
|
||||
|
||||
|
||||
// If we made it this far, we were given a data type that we're not actively supporting.
|
||||
// As such, we just have to hand this off to the native serializer.
|
||||
writeOutput( serializeJson( input ) );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* I serialize and write the given string to the current output context, escaping all appropriate
|
||||
* characters for the JSON specification.
|
||||
*
|
||||
* NOTE: We are using this manual-encoding process rather than the built-in serializeJson() function
|
||||
* as there is a rather nasty bug that corrupts certain patterns in the output. Read more:
|
||||
*
|
||||
* http://www.bennadel.com/blog/2842-serializejson-and-the-input-and-output-encodings-are-not-same-errors-in-coldfusion.htm
|
||||
*
|
||||
* @input I am the string being serialized.
|
||||
*/
|
||||
private void function serializeInputString( required string input ) {
|
||||
|
||||
// While this may not be technically needed, this will ensure that we are not using any
|
||||
// "undocumented features" of the language. If we explicitly cast to a Java string, and
|
||||
// something goes wrong due to odd type-casting, it's a ColdFusion bug, at that point, not
|
||||
// a logic error ;)
|
||||
input = javaCast( "string", input );
|
||||
|
||||
var length = input.length();
|
||||
|
||||
writeOutput( """" );
|
||||
|
||||
for ( var i = 1 ; i <= length ; i++ ) {
|
||||
|
||||
var charCode = input.codePointAt( javaCast( "int", i - 1 ) );
|
||||
|
||||
// Check for the most common case first (normal characters).
|
||||
if (
|
||||
( charCode >= 32 ) &&
|
||||
( charCode != 34 ) &&
|
||||
( charCode != 47 ) &&
|
||||
( charCode != 92 ) &&
|
||||
( charCode != 8232 ) &&
|
||||
( charCode != 8233 )
|
||||
) {
|
||||
|
||||
writeOutput( chr( charCode ) );
|
||||
|
||||
// Check for the special cases next (control characters, characters that
|
||||
// need to be escaped, and characters that need to be encoded nicely).
|
||||
} else if ( charCode == 8 ) {
|
||||
|
||||
writeOutput( "\b" );
|
||||
|
||||
} else if ( charCode == 9 ) {
|
||||
|
||||
writeOutput( "\t" );
|
||||
|
||||
} else if ( charCode == 10 ) {
|
||||
|
||||
writeOutput( "\n" );
|
||||
|
||||
} else if ( charCode == 12 ) {
|
||||
|
||||
writeOutput( "\f" );
|
||||
|
||||
} else if ( charCode == 13 ) {
|
||||
|
||||
writeOutput( "\r" );
|
||||
|
||||
} else if (
|
||||
( charCode < 32 ) ||
|
||||
( charCode == 8232 ) ||
|
||||
( charCode == 8233 )
|
||||
) {
|
||||
|
||||
// For Unicode hex values, we need to enforce a 4-digit code.
|
||||
writeOutput( "\u" & right( ( "000" & formatBaseN( charCode, 16 ) ), 4 ) );
|
||||
|
||||
} else if ( charCode == 34 ) {
|
||||
|
||||
writeOutput( "\""" );
|
||||
|
||||
} else if ( charCode == 47 ) {
|
||||
|
||||
writeOutput( "\/" );
|
||||
|
||||
} else if ( charCode == 92 ) {
|
||||
|
||||
writeOutput( "\\" );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
writeOutput( """" );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* I serialize and return the given string, escaping all appropriate characters for the
|
||||
* JSON specification.
|
||||
*
|
||||
* @input I am the string being serialized.
|
||||
* @output false
|
||||
*/
|
||||
private string function serializeString( required string input ) {
|
||||
|
||||
savecontent variable = "local.json" {
|
||||
|
||||
serializeInputString( input );
|
||||
|
||||
}
|
||||
|
||||
return( json );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
<cfcomponent extends="taffy.core.baseSerializer">
|
||||
|
||||
<cffunction
|
||||
name="getAsJson"
|
||||
output="false"
|
||||
taffy:mime="application/json"
|
||||
taffy:default="true">
|
||||
<cfreturn variables.jsonUtil.serialize(variables.data) />
|
||||
</cffunction>
|
||||
|
||||
<cffunction name="setJSONUtil" output="false">
|
||||
<cfargument name="JSONUtil" required="true" />
|
||||
<cfset variables.jsonUtil = arguments.JSONUtil />
|
||||
</cffunction>
|
||||
|
||||
</cfcomponent>
|
||||
Reference in New Issue
Block a user