“如何解决`删除SerializeJSON()的默认字母顺序`

时间:2019-04-18 03:15:59

标签: coldfusion cfml

我正在尝试将请求中的序列化数据添加到需要维护数据特定顺序的第三方API,但是SerializeJSON以字母顺序排序,这破坏了第三方API要求的格式。有人可以帮我弄清楚

输入:

<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"
                }
            }>

在我的数据上使用此方法SerializeJSON()时:

SerializeJSON(data)

当前输出

"{"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"}}}"

预期输出:

"{"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 个答案:

答案 0 :(得分:7)

ColdFusion中的结构是无序的HashMap,因此根本没有任何顺序。您可以使用structNew("Ordered")(ColdFusion 2016引入)来保持插入顺序。不幸的是,您不能再使用文字语法了,但是我认为您还是在动态地生成数据。

<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.

如果您使用的是较旧的ColdFusion版本,则必须使用Java的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.

但是请注意:LinkedHashMap区分大小写(并且还区分类型:如果您的键是数字,那很重要!)。

<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
--->

您可能会遇到的另一个问题:由于ColdFusion的内部类型转换,serializeJSON()可能会以意想不到的方式对数字和布尔值进行字符串化处理。像这样:

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

很容易像这样结束

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

(注意:上述文字语法完全可以正常工作,但是如果您将值作为变量/参数传递,则最终会进行强制转换。)

最简单的解决方法是在序列化之前显式转换值:

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