Saturday, August 18, 2018

ColdFusion member functions for XML object management

Prior to ColdFusion 2018, ColdFusion supported the following XML member functions:

Since ColdFusion also supports using array and structure functions to manage XML document objects, I filed CF-4199973 to add the relevant string, struct and array member functions on XML variables.

ColdFusion 2018 added the following XML member functions:

* - Covered by CF-4199973.

** - Pending in CF-4203285.

Observation 1:
.clear() would seemingly be ambiguous, since ArrayClear() and StructClear() can both be used on an XML object. However, ArrayClear(xml) actually *deletes* nodes and its functionality is already covered by StructDelete() and ArrayDeleteAt(). ArrayClear(xmlFoo.xmlBar) deletes all nodes named 'xmlBar' under xmlFoo (equivalent of StructDelete(xmlFoo, "xmlBar")). ArrayClear(xmlFoo.xmlBar[2]) deletes the second node named 'xmlBar' under xmlFoo (equivalent of ArrayDeleteAt(xmlFoo.xmlBar, 2)). So, xmlObject.clear()/XMLClear(xmlObject) should be added to cover StructClear(xmlObject)'s functionality. StructClear(xmlFoo.xmlBar) and StructClear(xmlFoo.xmlBar[1]) clear (convert to empty node) the first node named 'xmlBar' under xmlFoo. ArrayClear() Repro: https://trycf.com/gist/49487fe7e971236bafe0a6685374ca86/acf2018?theme=monokai. StructClear() Repro: https://trycf.com/gist/e04db3702a5bdbbe06de6896639452c5/acf2018?theme=monokai.
Observation 2:
No equivalent for StructDelete() was added. StructDelete(xmlFoo, "xmlBar") deletes all nodes named 'xmlBar' under xmlFoo. So, xmlObject.delete(childName)/XMLDelete(xmlObject, childName) should be added to cover StructDelete(xmlObject, childName)'s functionality. Repro: https://trycf.com/gist/493f0ae6ba00a7d2b528394fa36a1898/acf2018?theme=monokai.
Observation 3:
No equivalent for ArrayDeleteAt() was added. ArrayDeleteAt(xmlFoo.xmlBar, 2) deletes the second node named 'xmlBar' under xmlFoo. So, xmlObject.deleteAt(position)/XMLDeleteAt(xmlObject, position) should be added to cover ArrayDeleteAt(xmlObject, position)'s functionality. Repro: https://trycf.com/gist/1aa6b58603f20739907bfa21ff540ff5/acf2018?theme=monokai.
Observation 4:
Equivalent for Duplicate() exists in CF2016 for all data types. So, XMLDuplicate(xmlObject) does not need added. Repro: https://trycf.com/gist/87b44d40d3400dfa97b4d19911b58a07/acf2016?theme=monokai.
Observation 5:
.isEmpty() was not added because .hasChild() makes more sense in the context of XML and because it would've been ambiguous, since ArrayIsEmpty() and StructIsEmpty() can both be used on an XML object. ArrayIsEmpty(xmlFoo.xmlBar) returns YES if xmlFoo contains any nodes named 'xmlBar'. Whereas, StructIsEmpty(xmlFoo.xmlBar) returns YES if xmlBar contains any nodes. Repro: https://trycf.com/gist/9a73f736757625ecd6f6f9695c8fea65/acf2018?theme=monokai.
Observation 6:
.hasChild() currently doesn't work (always returns YES) and, if it did, only covers StructIsEmpty()'s functionality but not ArrayIsEmpty's. So, xmlObject.hasChild([childName])/XMLHasChild(xmlObject[, childName]) needs an optional 'childName' parameter, in order to also cover ArrayIsEmpty(xmlObject.childName)'s functionality. Repro: https://trycf.com/gist/0db692627ccefdfbe436e756988c10c1/acf2018?theme=monokai.
Observation 7:
No equivalent for Len() was added. Len(xmlObject) implicitly casts xmlObject to string and returns the string's length. However, IMO, an equivalent XML member function for Len(xmlObject) does not need added since: 1) it's undocumented functionality, 2) xmlObject.toString().len() covers its functionality and, more importantly IMO, 3) xmlObject.len() is needed to, and currently does, cover ArrayLen(xmlObject)'s functionality. Repro: https://trycf.com/gist/e0b20bf374a84f279f38974268813ec4/acf2018?theme=monokai.
Observation 8:
ArrayLen(), like a few of the others, is not completely documented. ArrayLen(xmlFoo.xmlBar) counts the nodes named 'xmlBar' under xmlFoo. See Repro for Observation 7.
Observation 9:
StructGet() does not support array notation when referencing an XML object. So, StructGet() needs fixed to support array notation when referencing an XML object. Repro: https://trycf.com/gist/baa6a4aeeec368e6567efe5cf827ee4c/acf2018?theme=monokai
Observation 10:
Since ToString() is not XML-specific, the XMLToString(xmlObject) BIF does not need added.
Observation 11:
Currently, xmlObject.update() returns a struct that doesn't contain, for example, the updated xmlText. So, xmlObject.update() needs fixed to return the updated XML. Repro: https://trycf.com/gist/4031ebc027c788574948183387b56b68/acf2018?theme=monokai
Observation 12:
The "Supported XML member functions" list isn't, but should be, alphabetical. And it should consistently use 'someVar' like the other member function list tables. And the list's purpose isn't for showing syntax, so "xmlObject.update(String key, Object value)" should just be "someVar.update()". And XmlLen/someVar.len() is missing and needs added. And .toString(), added to XML in CF2018, isn't listed but should be. And .duplicate() also exists on XML, but isn't listed and should be.

Once all the issues are fixed, the "Supported XML member functions" doc list should look like (w/ non-XML-specific at bottom):


# XmlAppend someVar.append()
XmlChildPos someVar.childPos()
# XmlClear someVar.clear()
# XmlCount someVar.count()
# XmlDelete someVar.delete()
# XmlDeleteAt someVar.deleteAt()
XmlElemNew someVar.elemNew()
XmlGetNodeType someVar.getNodeType()
# XmlHasChild someVar.hasChild()
# XmlLen someVar.len()
# XmlKeyArray someVar.keyArray()
# XmlKeyList someVar.keyList()
XmlSearch someVar.search()
XmlTransform someVar.transform()
# XmlUpdate someVar.update()
Duplicate someVar.duplicate()
# ToString someVar.toString()

# New in Adobe ColdFusion (2018 release)


Verified in build 2018.0.0.310739.
Filed observations #1, #2, #3, #6 and #11 as CF-4203285.
Filed observation #9 as CF-4203287.
Filed observation #12 as CF-4203286.

Friday, May 25, 2018

RE: Upgrade path to ColdFusion (2018 release)

This post is regarding the "Upgrade path to ColdFusion (2018 release)" post at the ColdFusion Community Portal. It looks like Adobe's website only offers the ColdFusion (2016 release) full license and not the upgrade license?

Steps to Reproduce: 1) Visit www.coldfusion.com
2) See this:

3) Click any of the "Buy Now" buttons
4) See this:

5) Go back www.coldfusion.com and scroll to the bottom
6) See this:

7) Click the Standard Edition's "Buy Now" button
8) See this:

Question: How does one choose the upgrade license?

Thursday, May 24, 2018

CF-4202602 - REST method compile time error says wrong file

Issue: REST method compile time error says wrong file

Steps to Reproduce:
1) unzip CF-4202602.zip (attached to ticket)
2) In CF Admin, create "mymapping" mapping to unzipped app's directory
3) run index.cfm to register REST app
4) run mypage.cfm

Actual Result:

The error occurred in {path}/MyCFC.cfc: line 4

2 : component rest=true restpath="a" {
3 :   remote string function returnVoid(string c restargsource="path") httpmethod="GET" restpath="b/{c}" produces="application/json" {
4 :     o = new mymapping.myOtherCFC();
5 :     return serializeJSON(ARGUMENTS.c == 'c' ? 'c' : '');
6 :   }

Expected Result:

The error occurred in {path}/MyOtherCFC.cfc: line 2

1 : component {
2 :   function f() {compileTime=}
3 : }

Note: If `function f() {compileTime=}` is changed to `compileTime` in MyOtherCFC.cfc, then error shows correct file:

The error occurred in {path}/MyOtherCFC.cfc: line 2

1 : component {
2 :   compileTime
3 : }

Note: If `o = new mymapping.myOtherCFC()` is called from a .cfm (i.e. not during REST call), then error also shows correct file.

Summary: The issue seems to only occur when a CFC *method* throws a compile time error during a *REST call*.

Verified in build 2018.0.01.308605 (PreRelease).
Filed as CF-4202602.

CF-4202597 - per-app mappings don't exist in REST CFCs

Issue: per-app mappings don't exist in REST CFCs

Steps to Reproduce:
1) unzip CF-4202597.zip (attached to ticket)
2) run index.cfm to register REST app
3) run mypage.cfm

Actual Result: coldfusion.xml.rpc.CFCInvocationException - Could not find the ColdFusion component or interface mymapping.myOtherCFC

Expected Result: "c"

4) In CF Admin, create "mymapping" mapping to unzipped app's directory
5) run mypage.cfm

Actual and Expected Result: "c"

Verified in build 2018.0.01.308605 (PreRelease).
Filed as CF-4202597.

Monday, May 21, 2018

CF-4202547 - CF2016 vs Aether wrt custom REST response via cfthrow

Issue: CF2016 vs Aether wrt custom REST response via cfthrow

History: Pre-Aether, cfthrow could be used to send a custom REST response as JSON. In Aether, this fails (returns HTML of error handler page).

Steps to Reproduce:
1) Unzip CF-4202547.zip (attached to ticket)
2) Run index.cfm to register the REST application
3) Run mypage.cfm and compare the output w/ the code comments in mypage.cfm

Actual Result: CF sends cfthrow's custom message as HTML of error handler page

Expected Result: CF sends cfthrow's custom message as JSON

Related URL: Getting Started with RESTful Web Services in ColdFusion

Verified in build 2018.0.01.308605 (PreRelease).
Filed as CF-4202547.
Summary:

Initially:
1) In non-void UDF, restSetResponse() was ignored
2) In void UDF, cfthrow returned custom REST response as HTML of error handler page (instead of JSON)

Both were filed as CF-3546046, but only #2 was fixed (which I've verified in CF2016 Update 1).

#1 was re-filed as CF-4198298.

In Aether Public Beta Update 1, #1 is fixed but #2's fix was reverted/undone/unfixed.

Filed CF-4202547 to re-fix #2.

CF-4202544 - NULL cannot be made final

Issue: NULL cannot be made final

Steps to Reproduce:
1) Run:

<cfscript>
  final null = null
  writeDump(null)
</cfscript>

Actual Result: coldfusion.runtime.UndefinedVariableException on line 2

Expected Result: [null]

Suggestion: `final null = null` should be allowed, to prevent NULL from being overridden

Verified in build 2018.0.01.308605 (PreRelease).
Filed as CF-4202544.

CF-4202543 - NULL is not final

Issue: NULL is not final

Steps to Reproduce:
1) Run:

<cfscript>
  null = "asdf"
  foo = variables.null
  bar = null
  writeDump(variables)
</cfscript>

Actual Result:

struct
BAR asdf
FOO asdf
NULL asdf

Expected Result:

struct
BAR [null]
FOO asdf
NULL asdf

2) Run:

<cfscript>
  function null() {
    var bar = null
    return bar
  }
  writeDump(null())
  writeDump(variables)
</cfscript>

Actual Result:

function null
Arguments: none
ReturnType: Any
Roles:  
Access: public
Output:  
DisplayName:  
Hint:  
Description:  
struct
NULL
function null
Arguments: none
ReturnType: Any
Roles:  
Access: public
Output:  
DisplayName:  
Hint:  
Description:  

Expected Result:

[null]
struct
NULL
function null
Arguments: none
ReturnType: Any
Roles:  
Access: public
Output:  
DisplayName:  
Hint:  
Description:  

Suggestions:
1) `bar=null` should always be shorthand for `bar=javaCast("null","")`
2) `var bar=null` should always be shorthand for `var bar=javaCast("null","")`
3) scoping is required, in order to set bar equal to the value of a variable named null (ex: `bar=variables.null` and `var bar=local.null`)

Verified in build 2018.0.01.308605 (PreRelease).
Filed as CF-4202543.

ColdFusion member functions for XML object management

Prior to ColdFusion 2018, ColdFusion supported the following XML member functions : .elemNew() (equivalent of XmlElemNew ) .childPos(...