Search code examples
coldfusionlucee

Issue migrating from Adobe Coldfusion 10 to Lucee 4.5.1 - accessing structure


I'm currently attempting to migrate my site from Adobe Coldfusion 10 to Lucee 4.5.1.

I'm getting the following error: key [TITLE] doesn't exist.

The code I was using was:

<cfset variables.title = ress.title.welcome>

The code that I need to fix the issue seems to be:

<cfset variables.title = ress["title.welcome"]>

I'm using JavaRB and loading a properties file (onRequestStart()) and setting it to the variable ress.

<cfset ress = utilObj.getResourceBundle()>

Is there an alternative other than going through my code to fix all the references? Is there a setting in the server to exhibit the old behavior?

Update #1

Properties files looks like this:

# @comment 
title.welcome=Content here

Update #2

This currently works on CF10 Developer on Windows 2008 R2 and CF10 on my shared host which is also Windows Server. I will also acknowledge that this is old code :)

JavaRB returns a structure from the content of the file:

var resourceBundle=structNew(); // structure to hold resource bundle
...
<cfreturn resourceBundle />

Partial CFC and method calls...

<cfcomponent name="utils" output="false">

    <cfset this.ress = "">

    <cffunction name="init">
        <cfscript>
            this.ress = loadResourceBundle();
        </cfscript>
        <cfreturn this>
    </cffunction>

    <cffunction name="loadResourceBundle" access="public" output="true">
        <!--- Get javaRB --->
        <cfinvoke component="#application.cfcPath#.javaRB" method="init" returnvariable="rb">
        </cfinvoke>
        <cfscript>
            rbFile = GetDirectoryFromPath(expandpath("/resources/")) & "mgs.properties";
        </cfscript>
        <cfreturn rb.getResourceBundle("#rbFile#")>
    </cffunction>
    ...
</cfcomponent>


<cfcomponent displayname="javaRB" output="no">
    <cffunction access="public" name="init" output="No">
        <cfscript>
            rB=createObject("java", "java.util.PropertyResourceBundle");
            fis=createObject("java", "java.io.FileInputStream"); 
            msgFormat=createObject("java", "java.text.MessageFormat");  
            locale=createObject("java","java.util.Locale");
        </cfscript>

        <cfreturn this>
    </cffunction>

    <cffunction access="public" name="getResourceBundle" output="No" returntype="struct" hint="reads and parses java resource bundle per locale">
        <cfargument name="rbFile" required="Yes" type="string" />
        <cfargument name="rbLocale" required="No" type="string" default="en_US" />
        <cfargument name="markDebug" required="No" type="boolean" default="false" />
        <cfscript>
            var isOk=false; // success flag
            var keys=""; // var to hold rb keys
            var resourceBundle=structNew(); // structure to hold resource bundle
            var thisKey="";
            var thisMSG="";
            var thisLang=listFirst(arguments.rbLocale,"_");
            var thisDir=GetDirectoryFromPath(arguments.rbFile);
            var thisFile=getFileFromPath(arguments.rbFile);
            var thisRBfile=thisDir & listFirst(thisFile,".") & "_"& arguments.rbLocale & "." & listLast(thisFile,".");
            if (NOT fileExists(thisRBfile)) //try just the language
                thisRBfile=thisDir & listFirst(thisFile,".") & "_"& thisLang & "." & listLast(thisFile,".");
            if (NOT fileExists(thisRBfile))// still nothing? strip thisRBfile back to base rb
                thisRBFile=arguments.rbFile;
            if (fileExists(thisRBFile)) { // final check, if this fails the file is not where it should be
                isOK=true;
                fis.init(thisRBFile);
                rB.init(fis);
                keys=rB.getKeys();
                while (keys.hasMoreElements()) {
                    thisKEY=keys.nextElement();
                    thisMSG=rB.handleGetObject(thisKey);
                    if (arguments.markDebug)
                        resourceBundle["#thisKEY#"]="****"&thisMSG;
                    else
                        resourceBundle["#thisKEY#"]=thisMSG;
                    }
                fis.close();
                }
        </cfscript> 
        <cfif isOK>
            <cfreturn resourceBundle />
        <cfelse>
            <cfthrow message="#e.message#" detail="#e.detail#" type="#e.type#" />
        </cfif>
    </cffunction>
    ...
</cfcomponent>

Update #3

FWIW, I used the Eclipse IDE and did a find replace using a regex and replaced it with a value...

regex: ((ress\.){1}(([a-z\.])+))

value: ress["$3"]

Update #4

So, using Lucee and MySQL, table names are case sensitive!?


Solution

  • Welcome to Adobe ColdFusion, where syntactical mistakes are not punished immediately.

    <cfset ress = { "title.welcome": "Content here" }>
    
    <cfoutput>#ress.title.welcome#</cfoutput>
    <!---
    
        >> outputs "Content here" in Adobe ColdFusion
        >> throws an exception in Lucee/Railo
    
    --->
    

    The behavior in Adobe ColdFusion is misleading and plain wrong. "title.welcome" is a key that is supposed to be put in the struct ress. Instead the key is split into two structs with the keys "title" and "welcome", linked to each other and then put into the struct ress.

    Your only chance to fix this issues is by adapting your getResourceBundle function. Here you need to refactor the lines with resourceBundle["#thisKEY#"] so that thisKEY creates a struct chain.