ColdFusion 9: nested implicit struct issue - coldfusion

I'm running into a strange issue when I try to use quoted key values in nested implicit structs.
<cfset outer = {
inner = {
standard = "works",
"quoted" = "does not work"
}
} />
<cfdump var=#outer.inner["quoted"]# />
This produces the error: Element quoted is undefined in a CFML structure referenced as part of an expression.
Dumping the entire outer struct shows no value there as well.
What's going on here?

Your code works for me. Are you on ColdFusion 9.0.1? I believe there were some bug fixes related to nested structs/arrays in 9.0.1. Try installing the updater if you have not.

Related

Does CF not support Java constructors with variable number of arguments and any known workarounds?

We have a project that deals with files of various encodings. I am using BOMInputStream to skip UTF-8 byte order markers. The existing code works but needs to also support UTF-16 variations. The most straight forward approach is to pass the BOMInputStream constructor multiple ByteOrderMarkers.
Per documentation...
BOMInputStream bomIn = new BOMInputStream(in,
ByteOrderMark.UTF_16LE,
ByteOrderMark.UTF_16BE,
ByteOrderMark.UTF_32LE,
ByteOrderMark.UTF_32BE);
The constructor signature uses variable arguments:
public BOMInputStream(InputStream delegate,
ByteOrderMark... boms)
However, when I try to call this constructor using the following code
<cfset var fis = createObject("java", "java.io.FileInputStream").init(arguments.filePath) />
<cfset var boms = createObject("java", "org.apache.commons.io.ByteOrderMark") />
<cfset var bomins = createObject("java", "org.apache.commons.io.input.BOMInputStream").init(fis, boms.UTF_8, boms.UTF_16LE, boms.UTF_16BE) />
I get the following error...
Unable to find a constructor for class org.apache.commons.io.input.BOMInputStream that accepts parameters of type ( java.io.FileInputStream, org.apache.commons.io.ByteOrderMark, org.apache.commons.io.ByteOrderMark, org.apache.commons.io.ByteOrderMark ).
I have tried just one BOM argument as well and get same error with fewer arguments in the error. So it appears that CF can't call Java constructors with unlimited arguments. Is that correct and, if so, is there any known work around?
Of course the moment I post an idea comes to me. It looks like these variables are accessed through an array in the Java object being called. I just changed the CF code to pass an array of BOMs instead of individual arguments and it worked as expected.
<cfset var bomins = createObject("java", "org.apache.commons.io.input.BOMInputStream").init(
fis,
[boms.UTF_8, boms.UTF_16LE, boms.UTF_16BE]
) />

Element VAR is undefined in ATTRIBUTES ColdFusion 11

I am trying to call a method from a java class but I am getting an exception I haven't seen before.
This is what I get back when I am calling the class and one of the methods and how I got this
<cfdump var="#nlp#">
<cfdump var="#nlp.run()#">
And this is the exception I got when I am trying to dump the method
19:12:31.031 - Expression Exception - in Z:/Sites/xamplifier/views/surveyreporting/wordcloud.cfm : line 157
Element VAR is undefined in ATTRIBUTES.
Am I calling the method in a wrong way? This is how we had the code on CF9 and everything works but CF 11 seems to have issues...
It looks like the Open_NPL run() method is generating an exception, which is caught and causes it to return null. See here: Open_NPS Source
Agree with the other answers, you'll just have to test for NULL to avoid the CF exception, and dig into the Java to determine the root cause.
The Java method is returning NULL, which in ColdFusion is the same as not being defined. You need to capture the result and test it.
<cfset local = {}><!--- if inside a function, this isn't necessary --->
<cfset local.result = nlp.run() >
<cfif not isNull( local.result ) >
<cfdump var="local.result">
<cfelse>
NULL!
</cfif>

Error while creating large dropdown in excel using ColdFusion

This code I have written for creating large dropdown in ColdFusion, but it is not working on my end. Could any one please help me rectify my problem. The new code is
<cfquery name="getPOP" datasource="l_webalc">
select distinct center_code from alc_pop
</cfquery>
<cfset countryName= ArrayNew(1)>
<cfloop query="getPOP">
<cfset arrayappend(countryName, getPOP.center_code)>
</cfloop>
<script>
workbook = new HSSFWorkbook();
realSheet = workbook.createSheet("Sheet xls");
hidden = workbook.createSheet("hidden");
for (int i = 0, length= countryName.length; i < length; i++) {
String name = countryName[i];
HSSFRow row = hidden.createRow(i);
HSSFCell cell = row.createCell(0);
cell.setCellValue(name);
}
namedCell = workbook.createName();
namedCell.setNameName("hidden");
namedCell.setRefersToFormula("hidden!A1:A" + countryName.length);
constraint = DVConstraint.createFormulaListConstraint("hidden");
addressList = new CellRangeAddressList(0, 0, 0, 0);
validation = new HSSFDataValidation(addressList, constraint);
workbook.setSheetHidden(1, true);
realSheet.addValidationData(validation);
stream = new FileOutputStream("c:\\range.xls");
workbook.write(stream);
stream.close();
</script>
Update 1:
(From other thread) I am getting this error message:
function keyword is missing in FUNCTION declaration. The CFML compiler
was processing: A script statement beginning with HSSFWorkbook on line
32, column 1. A script statement beginning with function on line 31,
column 9. A cfscript tag beginning on line 30, column 2.
Update 2:
Again I have modified this code and now the new error is
"The value hidden not A1:A cannot be converted to a number."
I edited the objects as mentioned in the comments and also changed the script to cfscript. Please help me to rectify this error.
<cfscript>
workbook = createObject("java", "org.apache.poi.hssf.usermodel.HSSFWorkbook");
realSheet = workbook.createSheet("Sheet xls");
hidden = workbook.createSheet("hidden");
for (i = 1; i <= arrayLen(countryName); i++){
name = countryName[i];
row = hidden.createRow(i);
cell = row.createCell(0);
cell.setCellValue(name);
}
namedCell = workbook.createName();
namedCell.setNameName("hidden");
namedCell.setRefersToFormula("hidden!A1:A"+arrayLen(countryName));
dv = createObject("java", "org.apache.poi.hssf.usermodel.DVConstraint");
constraint = dv.createFormulaListConstraint("hidden");
addressList = cellRangeList.init(0, 0, 0, 0);
validation = dataValidation.init(addressList, constraint);
workbook.setSheetHidden(1, true);
realSheet.addValidationData(validation);
stream = new FileOutputStream("c:\\range.xls");
workbook.write(stream);
stream.close();
</cfscript>
Update 3:
I have updated the code to fix the mentioned issues and and am now getting this error
"The setSheetHidden method was not found ..."
on the following line:
workbook.setSheetHidden(1, true);
There are several problems with your code. Though java syntax is similar, you cannot just copy and paste a java example and expect it to run in cfscript. You need to make some adjustments first. (Note: I am assuming script was just a typo for cfscript).
In java, you can instantiate an object using the keyword "new" ie new SomeClassName(). In CF, the new keyword can only be used with cfc's. To create a java object, you must use createObject instead. To instantiate it, call the init(...) method. It is a special method in CF that invoke's the constructor of a java class with whatever parameters you supply, ie
createObject("java", "path.to.SomeClassName").init();
To use static methods such as DVConstraint.createFormulaListConstraint(), you must also use createObject. While the java code does not create an new instance of that class, you must still use createObject to get a reference to the DVConstraint class, in CF, before you can invoke any of its methods. Note: Because it is static, no need to call init() first. ie
dv = createObject("java", "org.apache.poi.hssf.usermodel.DVConstraint");
dv.createFormulaListConstraint(...);
Java classes are organized into packages. In java classes, the full path to any referenced classes are imported at the top of the java code (not visible in the example you are using). In CF you need to use the full path in your createObject call. (Important: Paths are cAsE sEnsItIvE).
For example, instead of new HSSFWorkbook() use:
createObject("java", "org.apache.poi.hssf.usermodel.HSSFWorkbook");
If you are not sure of the path, just do a search on "POI TheClassName". Odds are the first result will be the POI JavaDocs, which show the full path at the top of each page like this:
java.lang.Object
|---org.apache.poi.ss.util.CellRangeAddressList
Unlike CF, java is strongly typed, which means you must declare a variable's type as well as it's name. For example, this line declares a variable row as type HSSFRow
HSSFRow row = hidden.createRow(i);
Since CF is typeless, it does not require a type. So running that same code in cfscript will cause the cryptic error "function keyword is missing...". The solution is to drop the variable type and just do a straight variable assignment:
row = hidden.createRow(i);
Java array indexes start at zero (0), while CF starts at one (1), so you need to fix the indexes in your for loop:
for (i = 1; i <= arrayLen(countryName); i++)
Java uses + to concatenate strings, whereas CF uses &. So you need to change the operator here "hidden!A1:A" + countryName.length. Otherwise CF will think you are trying to add two numbers, which will obviously throw an error because the first part is a string.
Assuming no version conflicts, the java example should work after you make those those adjustments.
"The setSheetHidden method was not found ..."
Just use Javacast function for boolean arguments:
workbook.setSheetHidden(1, javacast("boolean",true));

Using "var this" inside remote CFC methods

I've inherited a project where there are a number of remote CFC's opened up for some Ajax requests and inside most methods in the CFC have the following:
<cfset var this.response = true />
Now I've never seen the var and this scope used together like this so I'm really not sure what to make of it so I guess my questions is:
Are there any issues with how this was coded? If so, are they major enough that I should put in
the effort to update all the CFC's to something like <cfset var
req.response = true />?
Here is a quick example of what I'm seeing:
<cfcomponent>
<cffunction name="check_foo" access="remote" returnformat="plain">
<cfargument
name = "isfoo"
type = "string"
required = "false"
default = "nope"
hint = "I check the string for foo"
/>
<cfscript>
/*setup new response*/
var this.response = false;
/*check for foo*/
if( !findnocase( "foo", arguments.isfoo ) ) {
/*no foo!*/
this.response = false;
}
return this.response;
</cfscript>
</cffunction>
</cfcomponent>
.
Updates:
Based on the feedback/answers below I've replace all instances of var this. Thanks again to everyone that helped out!
.
update: upon checking your dump, the "this" in var this is still this this scope, not local.this.
It is setting the response to the this scope, and it works in this case because because the CFC is instantiated every time it's being invoked remotely. However, it'd be best to rename this into something else to ensure thread-safety in case the method is invoked by other CFC as public method.
Using var this is the same as using this.
Dumping the local scope will include local variables as well as the Arguments and This scopes. (Can't find this documented; but I get this result in a bare cfc, and you got it in your screenshots.)
Because your function is access="remote" you'll be getting a new instance of the cfc on every call, and therefore a bare This scope. So those are "safe", but still a bad idea.
If there is any use of var this in non-remote functions then you will be getting undesired persistence and may suffer race conditions that result is invalid data.
Relevant CF documentation:
"Methods that are executed remotely through Flash Remoting and web services always create a new instance of the CFC before executing the method."
"Variable values in the This scope last as long as the CFC instance exists and, therefore, can persist between calls to methods of a CFC instance."

Variable name in the method of ColdFusion Object

I am trying to set a variable in a cffunction.
The result is this:
<cfset local.layouts.appLayout = '../../app/layouts' & local.appController.new()>
The above code works. In the local.layouts.appLayout structure it assigns the return of the new method in the appControler. That is what I need it to do.
My problem is that I need to dynamically assign the method portion of that statement. I have another variable coreRoute.action that equals "new" in that function but I cannot seem to get the syntax right.
I have tried this:
<cfset local.layouts.appLayout = '../../app/layouts' & local.appController.coreRoute.action()>
That does not work and I can see why. I have also tried this:
<cfset local.layouts.appLayout = '../../app/layouts' & local.appController & #coreRoute.action# & '()'>
I have tried many variations of this syntax and I just cannot get it right.
Anyone have any ideas about how to do this. I am stuck.
Thanks in advance for any help.
UPDATE: With Todd Sharp's help I ended up using this and it worked great:
<cfinvoke component="#local.appController#" method="#coreRoute.action#" returnvariable="local.act">
<cfset local.layouts.appLayout = '../../app/layouts' & local.act>
You should look into using <cfinvoke> for dynamic method invocation. Try a Google search for "coldfusion dynamic method invocation" - here's one of the top results:
http://www.bennadel.com/blog/1320-ColdFusion-CFInvoke-Eliminates-The-Need-For-Evaluate-When-Dynamically-Executing-User-Defined-Functions.htm
In addition, if you want to do it entirely in script, you can, using this approach:
dynFn = this["foo" & bar];
dynFn(stuff);
This is in a cfc, if you're doing it from outside the cfc or not using a cfc at all, just change "this" to wherever your method is.