Copy link to clipboard
Copied
Tried searching to see if anyone has ran across the following issue after upgrading to CF2021.
In CF2016, it "seems" that CF is automatically converting data types based on the key values:
{"message":[],"code":"","success":true,"data":{"ID":15090910}} Notice the ID is int
In CF2021, the data type for the same exact code and request comes back a string:
{"message":[],"code":"","success":true,"data":{"ID":"15090889"}} Notice the ID is a string
I've already fixed some that are supposed to be boolean (true/false) rather coming back as ("true" / "false")
Is there a new setting I'm not aware of?
Is there a new setting I'm not aware of?
By @--jojo--
Yes. The setting this.serialization.structmetadata was later added to Application.cfc. For details see, for example, my comments in this previous forum thread on serializeJson.
If you want "success" to be of boolean type and "ID" to be of integer type throughout the application, then use
<!--- In Application.cfc --->
<cfset this.serialization.structmetadata = {success:"boolean", ID:"integer">
Copy link to clipboard
Copied
Is there a new setting I'm not aware of?
By @--jojo--
Yes. The setting this.serialization.structmetadata was later added to Application.cfc. For details see, for example, my comments in this previous forum thread on serializeJson.
If you want "success" to be of boolean type and "ID" to be of integer type throughout the application, then use
<!--- In Application.cfc --->
<cfset this.serialization.structmetadata = {success:"boolean", ID:"integer">
Copy link to clipboard
Copied
@BKBK - that's going to be a pain. Will it have to be just a structure of keys or will it have to match the exact structure of the object being serialized? (e.g. in my example above, ID is nested inside data)
Copy link to clipboard
Copied
Hi @--jojo-- ,
I don't think you have to recreate the struct's tree in the setting. With x.y.z.myKey, just a mention of myKey will be sufficient. To be sure, test it yourself.
For example, ensure the setting this.serialization.structmetadata is absent from your application. If it is present, comment it out.
Run the following code as a CFM page
<cfset x = {}>
<cfset x.myVar1 = "1234">
<cfset x.data.myVar2 = "5678">
<cfset x.data.amount1 = "123.45">
<cfset x.data.amount2 = "678.90">
<cfset x.myBool = 'true'>
<cfset x.myStr2 = 'false'>
<cfdump var="#SerializeJSON(x)#" >
The result should be a JSON in which every key and every value is a string.
Now, add the following line to Application.cfc:
<cfset this.serialization.structmetadata=
{ myVar2:"integer",
myBool:"boolean",
amount2: "numeric"
}>
Rerun the CFM page.
In the resulting JSON the data types of myVar2, myBool and amount2 have changed, respectively, to integer, boolean and numeric. The keys have different locations in the tree structure of the struct.
Copy link to clipboard
Copied
That make sense @BKBK. Thank you for the clarification. I guess we'll have to start keeping track of all these keys.
Copy link to clipboard
Copied
@BKBK - follow up question regarding this setting -
given the following setting
this.serialization.structmetadata= { itemid:"integer" };
In some cases the itemid (or whatever else key) could be empty, the serializeJSON function throws an error:
Message | empty String |
StackTrace | java.lang.NumberFormatException: empty String at java.base/jdk.internal.math.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1842) at java.base/jdk.internal.math.FloatingDecimal.parseDouble(FloatingDecimal.java:110) at java.base/java.lang.Double.parseDouble(Double.java:543) at coldfusion.runtime.JSONUtils.serializeJSONMap(JSONUtils.java:707) at coldfusion.runtime.JSONUtils.serializeJSONBase(JSONUtils.java:492) at coldfusion.runtime.JSONUtils.serializeJSONMap(JSONUtils.java:737) at coldfusion.runtime.JSONUtils.serializeJSONBase(JSONUtils.java:492) at coldfusion.runtime.JSONUtils.serializeJSONMap(JSONUtils.java:737) at coldfusion.runtime.JSONUtils.serializeJSONBase(JSONUtils.java:492) at coldfusion.runtime.JSONUtils.serializeJSON(JSONUtils.java:216) at coldfusion.runtime.JSONUtils.serializeJSON(JSONUtils.java:197) at coldfusion.runtime.JSONUtils.serializeJSON(JSONUtils.java:187) at coldfusion.runtime.JSONUtils.serializeJSON(JSONUtils.java:174) at coldfusion.runtime.CFPage.SerializeJSON(CFPage.java:12989) at cfSUGboxAPI2ecfm1975307115.runPage(C:\signupgenius\rocks\SUGboxAPI.cfm:183) at coldfusion.runtime.CfJspPage.invoke(CfJspPage.java:257) at coldfusion.tagext.lang.IncludeTag.handlePageInvoke(IncludeTag.java:749) at coldfusion.tagext.lang.IncludeTag.doStartTag(IncludeTag.java:578) at coldfusion.runtime.CfJspPage._emptyTcfTag(CfJspPage.java:5201) at cfApplication2ecfc1055429981$funcONREQUEST.runFunction(C:\signupgenius\rocks\Application.cfc:211) at coldfusion.runtime.UDFMethod.invoke(UDFMethod.java:623) at coldfusion.runtime.UDFMethod$ArgumentCollectionFilter.invoke(UDFMethod.java:516) at coldfusion.filter.FunctionAccessFilter.invoke(FunctionAccessFilter.java:95) at coldfusion.runtime.UDFMethod.runFilterChain(UDFMethod.java:463) at coldfusion.runtime.UDFMethod.runFilterChain(UDFMethod.java:438) at coldfusion.runtime.UDFMethod.invoke(UDFMethod.java:310) at coldfusion.runtime.TemplateProxy.invoke(TemplateProxy.java:975) at coldfusion.runtime.TemplateProxy.invoke(TemplateProxy.java:696) at coldfusion.runtime.TemplateProxy.invoke(TemplateProxy.java:503) at coldfusion.runtime.AppEventInvoker.invoke(AppEventInvoker.java:115) at coldfusion.runtime.AppEventInvoker.onRequest(AppEventInvoker.java:308) at coldfusion.filter.ApplicationFilter.invoke(ApplicationFilter.java:569) at coldfusion.filter.RequestMonitorFilter.invoke(RequestMonitorFilter.java:43) at coldfusion.filter.MonitoringFilter.invoke(MonitoringFilter.java:40) at coldfusion.filter.PathFilter.invoke(PathFilter.java:162) at coldfusion.filter.IpFilter.invoke(IpFilter.java:45) at coldfusion.filter.ExceptionFilter.invoke(ExceptionFilter.java:97) at coldfusion.filter.ClientScopePersistenceFilter.invoke(ClientScopePersistenceFilter.java:28) at coldfusion.filter.BrowserFilter.invoke(BrowserFilter.java:38) at coldfusion.filter.NoCacheFilter.invoke(NoCacheFilter.java:60) at coldfusion.filter.GlobalsFilter.invoke(GlobalsFilter.java:38) at coldfusion.filter.DatasourceFilter.invoke(DatasourceFilter.java:22) at coldfusion.filter.CachingFilter.invoke(CachingFilter.java:62) at coldfusion.filter.RequestThrottleFilter.invoke(RequestThrottleFilter.java:151) at coldfusion.CfmServlet.service(CfmServlet.java:231) at coldfusion.bootstrap.BootstrapServlet.service(BootstrapServlet.java:311) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) at coldfusion.monitor.event.MonitoringServletFilter.doFilter(MonitoringServletFilter.java:46) at coldfusion.bootstrap.BootstrapFilter.doFilter(BootstrapFilter.java:47) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) at coldfusion.inspect.weinre.MobileDeviceDomInspectionFilter.doFilter(MobileDeviceDomInspectionFilter.java:57) at coldfusion.bootstrap.BootstrapFilter.doFilter(BootstrapFilter.java:47) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:377) at org.apache.coyote.ajp.AjpProcessor.service(AjpProcessor.java:463) at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:889) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1743) at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.base/java.lang.Thread.run(Thread.java:834) |
Is there a way to get around this?
Copy link to clipboard
Copied
I don't understand why you would want to by-pass the validation. ColdFusion is doing precisely what you want. The setting
this.serialization.structmetadata= { itemid:"integer" };
is you telling ColdFusion that, should it encounter any struct with key itemId, the value must be an integer.
I can think of 3 ways to get around this:
<cfset myStruct = {}>
<cfset myStruct.itemId = "">
<cftry>
<cfset myJSON = serializeJSON(myStruct)>
<cfcatch type="any" >
<cfif trim(myStruct.itemId) == "">
<cfset myStruct.itemId = -1><!--- Or 0, for example: to mean invalid integer --->
<cfset myJSON = serializeJSON(myStruct)>
<!---<cfdump var="#myJSON#">--->
<cfelse>
<!--- Handle error: myStruct.itemId is neither integer nor empty string --->
</cfif>
</cfcatch>
</cftry>
Copy link to clipboard
Copied
So I don't think I explained what I was trying to ask, but you shed light as to why the serializeJSON() throws an error when the value is missing. I didn't realize that defining keys and types using
this.serialization.structmetadata
is a strict validation. Basically what I was hoping is that the validation is more like...
this.serialization.structmetadata = {name:"itemid", type:"integer", required:false};
I know this is not the syntax, but if the value of itemid is empty or null, the validation ignores it.
We may have to resort to #3 option as you suggested and just validate the value where needed.
Thanks!
Jojo
Copy link to clipboard
Copied
Ah, I see.