CF casts Class instances to a String

Description

<cfscript> v = getMetadata( 42 ) // lucee: "double" // acf: "integer" // box: In function [listLast], argument [list] with a type of [java.lang.Class] does not match the declared type of [string] writedump( listLast( v, ". " ) ); </cfscript>

Activity

Show:

Brad Wood January 28, 2025 at 8:54 PM

I have added the ability to cast a class to a string in the StringCaster and placed it behind a static flag (off by default) called castClassesToStrings which the compat module will toggle to true.

Brad Wood January 14, 2025 at 6:20 PM

listLast( toString( getMetadata( arguments.value ).name ), ". " )

Even that is significantly over-built. All that is needed is

arguments.value.getClass().getSimpleName()

Works on all 3 engines, and works for all objects except CFCs.

Jon Clausen January 14, 2025 at 2:58 PM

can you clarify why you didn’t use listLast( toString( getMetadata( arguments.value ).name ), ". " ) and ran listToArray on the metadata object? I would tend to agree with Brad that stringification of classes that simply converts them to their class name in our list methods seems kind of ugly.

David Rogers January 14, 2025 at 2:42 PM

Yes, "java.lang.Class objects are implicitly converted to string in a myriad of adhoc contexts" is very dynamic behavior. I would classify this as a fidelity-of-compatibility concern. I agree that 100% fidelity is probably impossible due to differences in exception error messages or particular physical representations of numbers, and things of that nature.

The code triggering this error in our application is from here:
https://github.com/coldbox-modules/qb/blob/57270ada128947662f10db7f6be62a0817f3fb4c/models/Query/QueryUtils.cfc#L464

Though I have an older version of this library - with a more recent version having a workaround of an explicit cast-to-string for this difference in behavior:
https://github.com/coldbox-modules/qb/blob/3ed8b49915ed3c706f0f8576dad4feae28374ba9/models/Query/QueryUtils.cfc#L475

(see commit bebc83d515ff8e802bfa5d2d4552c10e3b176271)

So there's at least one instance of this {having existed, existing} in the wild, where the resolution was to change the CF program rather than maintain engine compatibility. I'm not sure how widespread this issue is - it might be that the Right Move really is to just change the CF source text.

Brad Wood January 14, 2025 at 12:05 AM
Edited

I'm not sure I’m following the intent of this code. The getMetaData() simply returns the Java Class for any incoming variable which is not a known CF type such as query, array, or struct. So the getMetaData( 42 ) bit literally just returns the java.lang.Class for the type it represents. In fact, if you run the following code on try CF, you get the same basic dump for all 3 engines.

writedump( getMetadata( 42 ) )

the only difference, being that Lucee uses a Double (unnecessary) and ACF and BoxLang both use an Integer. The idea that you can pass a Java Class instance into a function accepting a string isn’t anything that makes sense to me. I can only assume that Lucee and Adobe’s String caster will automatically turn a Java class instance into a string, which is the name of the class, which doesn’t seem like a particularly useful behavior.

Hmm, it actually works. Mind boggling

myNum = 42 writedump( ucase( myNum.getClass() ) )

Adobe and Lucee are also annoyingly inconsistent in when they will cast a class to a string.

myNum = 42 writedump( myNum.getClass().reverse() )

This errors for both of them, which is disappointing. Classes are apparently only strings when they want them to be.

If I make BoxLang decide that classes can now be treated as strings, it means code like that string member method WILL work. But should it really? Seems pretty ugly to me. Perhaps you can explain why you are attempting to treat Java classes as strings, which is an undocumented “feature” of CFML so far as I’m aware.

Fixed
Pinned fields
Click on the next to a field label to start pinning.

Details

Assignee

Reporter

Fix versions

Priority

Sentry

Created January 13, 2025 at 11:42 PM
Updated January 28, 2025 at 8:54 PM
Resolved January 28, 2025 at 8:53 PM