"How to fix `remove default alphabetical ordering of SerializeJSON() `

好久不见. 提交于 2019-12-23 09:33:23

问题


I'm trying to add the serialized data in a request to third party API which needs a specific order of the data to be maintained, but SerializeJSON orders in alphabetical order which breaks the format required by the third party API. Could someone help me to figure it out

INPUT:

<cfset data ={
                "Booking": {
                    "ActionCode":"DI",
                    "AgencyNumber":"23",
                    "Touroperator":"TVR",
                    "BookingNumber":"323",
                },
                "Payment": {
                    "__type":"paymenttype",
                    "PaymentProfile": {
                        "Value": 4,
                        "Manual": false
                    },
                    "PaymentType": 4,
                    "PaymentAction":2,
                    "Details": {
                        "IBAN": "DE02120300000000202051",
                        "BIC": "BYLADEM1001"
                    }
                },
                "Login":{
                    "UserCode": "usercode",
                    "Password": "password"
                }
            }>

When this method SerializeJSON() is used on my data:

SerializeJSON(data)

Current Output

"{"Booking":{"Touroperator":"TVR","ActionCode":"DI","BookingNumber":"323","AgencyNumber":"23"},"Login":{"UserCode":"usercode","Password":"password"},"Payment":{"PaymentProfile":{"Manual":false,"Value":4},"PaymentType":4,"PaymentAction":2,"__type":"paymenttype","Details":{"BIC":"BYLADEM1001","IBAN":"DE02120300000000202051"}}}"

Expected Output:

"{"Booking":{"ActionCode":"DI","AgencyNumber":"23","Touroperator":"TVR","BookingNumber":"323",},"Payment":{"__type":"paymenttype","PaymentProfile":{"Value":4,"Manual":false},"PaymentType":4,"PaymentAction":2,"Details":{"IBAN":"DE02120300000000202051","BIC":"BYLADEM1001"}},"Login":{"UserCode":"usercode","Password":"password"}}"

回答1:


Structs in ColdFusion are unordered HashMaps, so there is no order at all. You can keep insertion order by using structNew("Ordered") (introduced with ColdFusion 2016). Unfortunately you can no longer use the literal syntax anymore, but I assume you are generating the data dynamically anyway.

<cfset data = structNew("Ordered")>

<cfset data["Booking"] = structNew("Ordered")>
<cfset data["Booking"]["ActionCode"] = "DI">
<cfset data["Booking"]["AgencyNumber"] = "TVR">
<cfset data["Booking"]["BookingNumber"] = "323">

<cfset data["Payment"] = structNew("Ordered")>
<cfset data["Payment"]["__type"] = "paymenttype">
<cfset data["Payment"]["PaymentProfile"] = structNew("Ordered")>
<cfset data["Payment"]["PaymentProfile"]["Value"] = 4>
<cfset data["Payment"]["PaymentProfile"]["Manual"] = false>

etc.

If you are stuck on an older ColdFusion version, you will have to use Java's LinkedHashMap.

<cfset data = createObject("java", "java.util.LinkedHashMap")>

<cfset data["Booking"] = createObject("java", "java.util.LinkedHashMap")>
<cfset data["Booking"]["ActionCode"] = "DI">
<cfset data["Booking"]["AgencyNumber"] = "TVR">
<cfset data["Booking"]["BookingNumber"] = "323">

<cfset data["Payment"] = createObject("java", "java.util.LinkedHashMap")>
<cfset data["Payment"]["__type"] = "paymenttype">
<cfset data["Payment"]["PaymentProfile"] = createObject("java", "java.util.LinkedHashMap")>
<cfset data["Payment"]["PaymentProfile"]["Value"] = 4>
<cfset data["Payment"]["PaymentProfile"]["Manual"] = false>

etc.

But be aware: LinkedHashMap is case-sensitive (and also type-sensitive: in case your keys are numbers, it does matter!).

<cfset data = createObject("java", "java.util.LinkedHashMap")>

<cfset data["Test"] = "">
<!---
    accessing data["Test"] = works
    accessing data["test"] = doesn't work
    accessing data.Test    = doesn't work
--->

Another issue you might encounter: Due to ColdFusion's internal type casting, serializeJSON() might stringify numbers and booleans in an unintended way. Something like:

<cfset data = structNew("Ordered")>
<cfset data["myBoolean"] = true>
<cfset data["myInteger"] = 123>

could easily end up like:

{
    "myBoolean": "YES",
    "myInteger": 123.0
}

(Note: The above literal syntax would work perefectly fine, but if you are passing the values around as variables/arguments, casting eventually happens.)

The easiest workaround is explicitly casting the value before serializing:

<cfset data = structNew("Ordered")>
<cfset data["myBoolean"] = javaCast("boolean", true)>
<cfset data["myInteger"] = javaCast("int", 123)>


来源:https://stackoverflow.com/questions/55738639/how-to-fix-remove-default-alphabetical-ordering-of-serializejson

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!