3

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

TechFanDan
  • 3,329
  • 6
  • 46
  • 89
  • What does the properties file entry look like? – Leigh Nov 07 '15 at 23:29
  • @Leigh See update #1, that's what it looks like. – TechFanDan Nov 08 '15 at 00:52
  • A plain vanilla [ResourceBundle](https://docs.oracle.com/javase/8/docs/api/java/util/ResourceBundle.html) would treat "title.welcome" as a single key, so I would not have expected it be handled as a nested structure, as you described, in any engine. What kind of object is `utilObj` and what kind of object does `getResourceBundle()` return? – Leigh Nov 08 '15 at 10:04
  • @Leigh See update #2, I've put relevant CFC/method calls... – TechFanDan Nov 08 '15 at 10:47
  • Okay, so the issue is really that ACF treats structure key names containing a ".", like `myStruct["title.welcome"]`, as nested structures, while Lucee does not. Offhand, I do not know if there is a setting that changes the behavior. If not, you could always DIY. Create a function to split key names containing a "." and create the nested structures manually. Not the slickest option, but it would work. – Leigh Nov 08 '15 at 11:17
  • @leigh table names are case-sensitive now, being on Linux/Lucee/MySQL? – TechFanDan Nov 10 '15 at 12:50
  • 1
    Database table names? See [Are table names in MySQL case sensitive?](http://stackoverflow.com/questions/6134006/are-table-names-in-mysql-case-sensitive) – Leigh Nov 10 '15 at 15:15

1 Answers1

4

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.

Alex
  • 7,743
  • 1
  • 18
  • 38
  • thanks, I'll have a look at this. Currently on a shared Windows Server / SQL Server host and contemplating migrating to Linux / Lucee / MySQL... I keep meeting these sorts of things on the way :) – TechFanDan Nov 08 '15 at 11:44
  • 1
    Agreed. It only "works" by exploiting ACF's strange handling of structure key names containing a period. As I said above, I would not have expected it to work that way - in any engine. – Leigh Nov 08 '15 at 13:42