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>
Related
I have cfcatch block that should catch any exception. Once error detected I build custom function that takes NativeErrorCode as an argument. If error code is one that I'm looking for that indicates duplicate/PK violation I have custom message that will return to the user. If error code is not one that I'm looking for then global message will be returned. However, I run in the problem where ColdFusion returned error message that NativeErrorCode does not exist. I know that Native Error Code is reserved for database type. Is there a way to check the type and prevent this problem or there is better way to fix this issue? Here is my code example:
<cftry>
// Stored procedure call
<cfcatch type="any">
<cfset local.fnResults = {status : "400", message : Application.functions.errorCatch(cfcatch.NativeErrorCode)}>
</cfcatch>
</cftry>
public string function errorCatch(required string ErrorCode) {
local.message = "";
if(arguments.ErrorCode EQ 2627){
local.message = "Error! Cannot insert duplicate value.";
}else{
local.message = "Error! Please contact your administrator.";
}
return message;
}
You can see above how my errorCatch function works and what code I'm checking. I still want cfcatch to grab any exception in my code not just database errors.
Two ways come to mind for handling your branching catch logic, have 2 catch blocks, or check the catch object has the data you want.
In my first example I added a catch block exclusively for database errors. If the type of the error is database a Native Error Code will be included or be -1 if the database driver doesn't include one. For the any argument, I just added your default return string. You may want to have custom logic that would handle non-database type exceptions.
<cftry>
// Stored procedure call
<cfcatch type="database">
<cfset local.fnResults = {status : "400", message : Application.functions.errorCatch(cfcatch.NativeErrorCode)}>
</cfcatch>
<cfcatch type="any">
//Non database related error
<cfset local.fnResults = "Error! Please contact your administrator.">
</cfcatch>
</cftry>
In my second Example I just updated your errorCatch function with a check that a NativeErrorCode exist before we try to pass it.
<cfcatch type="any">
//Passing the default error code value, you may want custom logic here
<cfset local.fnResults = {
status : "400",
message : Application.functions.errorCatch( cfcatch.keyExists("NativeErrorCode")?cfcatch.NativeErrorCode:-1)
}>
</cfcatch>
I have the following code:
<cfset csvFilename = 'myCSV.csv'>
<cfset fileWriter = createobject("java","java.io.FileWriter").init("#csvFileName#")>
<cfset csvWriter = createObject("java","com.opencsv.CSVWriter").init(fileWriter, ",")>
<cfset csvWriter.writeNext('{"1","2"}', true)>
<cfset csvWriter.flush()>
<cfset fileWriter.close()>
<cfset csvWriter.close()>
When I run the page I get this error message:
The writeNext method was not found.
Either there are no methods with the specified method name and
argument types or the writeNext method is overloaded with argument
types that ColdFusion cannot decipher reliably. ColdFusion found 0
methods that match the provided arguments. If this is a Java object
and you verified that the method exists, use the javacast function to
reduce ambiguity.
I have searched the internet and cannot seem to find any examples of using csvWriter with Coldfusion and I am not sure why it is not working. I have a working example of csvReader and ReadNext, but not WriteNext. Any ideas of what I am doing wrong? I have tried to do a javacast but that didn't work either.
<cfset csvWriter.writeNext(javacast("string",'1,2'))>
I am using Coldfusion 11 with opencsv-3.8.jar
According to the API, that overload of writeNext() expects a String[], or an array of Strings. CF arrays are a little different than Java's, but they are compatible. Either of these would work:
<cfset csvWriter.writeNext( ["1","2"], true)>
<cfset csvWriter.writeNext( javacast("String[]", ["3","4"]), javacast("boolean", true))>
As an aside, skip the call to fileWriter.close(). When you call CSVWriter.close(), it closes the underlying writer for you. Calling both will cause an error.
<cfset csvFilename = 'myCSV.csv'>
Without a full path, I am not sure where that file will end up. Always specifying a full path can save a lot of head scratching later on ;-)
I am currently trying to capture all errors in my application by including the following code in Application.cfc:
<cffunction name="onError">
<!--- The onError method gets two arguments:
An exception structure, which is identical to a cfcatch variable.
The name of the Application.cfc method, if any, in which the error
happened. --->
<cfargument name="Except" required=true/>
<cfargument type="String" name = "EventName" required=true/>
<!--- Log all errors in an application-specific log file. --->
<cflog file="#THIS.NAME#" type="error" text="Event Name: #Eventname#" >
<cflog file="#THIS.NAME#" type="error" text="Message: #Except.message#">
<!--- Throw validation errors to ColdFusion for handling. --->
<cfif Find("coldfusion.filter.FormValidationException", Arguments.Except.StackTrace)>
<cfthrow object="#Except#">
<cfelse>
<cfoutput>
<h1>#Eventname#</h1>
</cfoutput>
<cfdump var="#Except#">
</cfif>
</cffunction>
Some of that is borrowed from other examples I have seen (which I don't fully understand). I ultimately want to show some kind of graceful error page to solicit feedback from the user and then log/email the error. This seems to catch a lot of errors, but not all. I don't want to use try/catch everywhere if I don't have to either. Any suggestions?
There is also an overall ColdFusion error handler that you can define in the ColdFusion administrator. Under the Server Settings > Settings, scroll down to the bottom and set the option for "Site-wide Error Handler".
Check this in the docs as well About error handling in ColdFusion
Using shared hosting shouldnt be an issue, just ask your hosr what the error templates are, if they are clued up about cf then they will have them setup.
Wr use error.cfm and 404.cfm fot example which go in the root of every customers site.
The "OnError" method within the Application.cfc will only catch the errors where they have not previously been caught by a user defined try/catch statement.
http://livedocs.adobe.com/coldfusion/8/htmldocs/help.html?content=appFramework_13.html
With this said, I think it to be a good idea to have try catch statements within your code where necessary (situations where you cannot degrade gracefully). What I like to do is instantiate a cfc that wraps all exception handling. This cfc can then contain the actual error handling logic and all that the OnError method will need to do is instantiate the correct component and "control" the error.
A very simple illustration:
<cfscript>
/** Application.cfc **/
public function onError(required exception, required string eventName)
{
var factory = new App.ExceptionFactory();
var e = factory.getNewException(arguments.eventName, arguments.exception);
if (e.logError()) {
/** we cauld also have a logging cfc etc **/
var loggingFile = new App.SomeLoggingCfc(arguments.eventName, arguments.exception);
loggingFile.commitLog();
}
if (e.debugError()) {
// show developer info here
}
/** Throw the exception **/
e.throwException();
}
/** App.ExceptionFactory **/
public ExceptionFactory function getNewException(required string eventName, required exception)
{
return new "App.#exception.type#"(argumentCollection = arguments);
}
/** App.Exception.CustomException **/
public boolean function logError()
{
/** log the error **/
}
public boolean function debugError() {}
public function throwException()
{
/** do what you want here **/
}
</cfscript>
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."
I'm attempting to build a method call from strings that have been passed into an object that refer to another object.
normally when calling an object we write the code like this:
application.stObj.oNewsBusiness.getNews(argumentCollection=local.stArgs);
However what I have done is created an array that contains the object name, the method name and the argument collection.
<cfscript>
local.stArgs = {};
local.stArgs.nNewsID = 19;
local.stArgs.sAuthor = "John";
local.aData = [];
local.aData[1] = local.stArgs;
local.aData[2] = "stObj.oNewsBusiness";
local.aData[3] = "getNews";
</cfscript>
however i am struggling to recombine all this to be a method call.
UPDATE using suggestion but still with issue
While cfinvoke seems to work for:
<cfinvoke component="#application.stObj.oNewsBusiness#" method="#local.sMethod#" argumentcollection="#local.stArgs#" returnvariable="local.qData"></cfinvoke>
it doesn't work when doing something like:
<cfscript>
local.stArgs = local.aData[1];
local.sObject = local.aData[2];
local.sMethod = local.aData[3];
</cfscript>
<cfinvoke component="application.#local.sObject#" method="#local.sMethod#" argumentCollection="#local.stArgs#" returnvariable="local.qData"></cfinvoke>
it generates an error:
Could not find the ColdFusion component or interface application.stObj.oNewsBusiness
CFInvoke is generally used to handle dynamic method calls.
http://help.adobe.com/en_US/ColdFusion/9.0/CFMLRef/WSc3ff6d0ea77859461172e0811cbec22c24-7e0a.html
CFInvoke has an argumentcollection attribute so you can pass your arguments in the way you are used to.
Dan is correct CFInvoke is the way to go
<cfinvoke component="#mycomponentname#" method="get" arg1="#arg1#" arg2="#arg2#" arg3=..>
<cfinvoke component="application.#local.sObject#" method="#local.sMethod#"argumentCollection="#local.stArgs#" returnvariable="local.qData"></cfinvoke>
from your update won't work because there are no # signs around the component variable.
You could do
<cfset local.componentName = "application." & local.sObject>
<cfinvoke component="#local.componentName#" method="#local.sMethod#"argumentCollection="#local.stArgs#" returnvariable="local.qData"></cfinvoke>
There's probably an inline way of combining application. with the variable on the cfinvoke call, but I don't know off the top of my head.
Edit: Dan Wilson's comment does it better in an inline way.