I've been working on a Braintree integration in ColdFusion. Braintree does not directly support CF, but they provide a Java library and everything I've done so far has worked really well... until now. It appears that some of the objects (particularly the search functionality) have methods that are not accessible from CF and I suspect it's because they are CF reserved words, such as "is" and "contains". Is there any way to get around this?
<cfscript>
gate = createObject( "java", "com.braintreegateway.BraintreeGateway" ).init(env,merchant.getMerchantAccountId(), merchant.getMerchantAccountPublicSecret(),merchant.getMerchantAccountPrivateSecret());
req = createObject( "java","com.braintreegateway.CustomerSearchRequest").id().is("#user.getUserId()#");
customer = gate.customer().search(req);
</cfscript>
The error thrown: Invalid CFML construct ... ColdFusion was looking at the following text: is
This represents a bug in the CF compiler. There is no rule in CF that one cannot define a method called either is() or this(), and indeed in basic situations there's no problem with calling them either. This code demonstrates:
<!--- Junk.cfc --->
<cfcomponent>
<cffunction name="is">
<cfreturn true>
</cffunction>
<cffunction name="contains">
<cfreturn true>
</cffunction>
</cfcomponent>
<!--- test.cfm --->
<cfset o = new Junk()>
<cfoutput>
#o.is()#<br />
#o.contains()#<br />
</cfoutput>
This - predictably - outputs:
true
true
However we have problems if we introduce a init() method to Junk.cfc, thus:
<cffunction name="init">
<cfreturn this>
</cffunction>
And then adjust test.cfm accordingly:
#o.init().is()#<br />
#o.init().contains()#<br />
This causes a compiler error:
Invalid CFML construct found on line 4 at column 19.
ColdFusion was looking at the following text:
is
[...]
coldfusion.compiler.ParseException: Invalid CFML construct found on line 4 at column 19.
at coldfusion.compiler.cfml40.generateParseException(cfml40.java:12135)
[etc]
There is no valid reason why o.init().is() should not be OK if o.is() is fine.
I recommend you file a bug. I'll vote for it.
As a workaround you should be fine if you use intermediary values, rather than method chaining.
You can probably use the Java Reflection API to invoke the is() method on your object.
I'd also raise a call with Adobe to see if they'll fix it or provide their own workaround. I can understand disallowing defining your own method or variable called 'is', but attempting to invoke it here should be safe.
Here is a solution to this problem. At least a fix to get you up and running.
Try this code.
<cfscript>
//Get our credentials here, this is a custom private function I have, so your mileage may vary
credentials = getCredentials();
//Supply the credentials for the gateway
gateway = createObject("java", "com.braintreegateway.BraintreeGateway" ).init(credentials.type, credentials.merchantId, credentials.publicKey, credentials.privateKey);
//Setup the customer search object
customerSearch = createObject("java", "com.braintreegateway.CustomerSearchRequest").id();
//can't chain the methods here for the contains, since it's a reserved word in cf. lame.
customerSearchRequest = customerSearch.contains(arguments.customerId);
//Build the result here
result = gateway.customer().search(customerSearchRequest);
</cfscript>
Related
I am trying to use Elasticsearch's Java API.
I am trying to create a RestClientBuilder.
Host=createObject("java", "org.apache.http.HttpHost").init(variables.HostName, variables.Port);
Node=createObject("java", "org.elasticsearch.client.Node").init(Host);
RestClient=createObject("java", "org.elasticsearch.client.RestClient").builder(Javacast("org.elasticsearch.client.Node[]", [Node])).build();
I get the error
Cannot convert the value to Java array because type org.elasticsearch.client.Node is unknown.
Also if I just try to use:
RestClient=createObject("java", "org.elasticsearch.client.RestClient").builder(Javacast("org.apache.http.HttpHost[]", [Host]));
I get the following error
Either there are no methods with the specified method name and
argument types or the builder 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.
This I assume is because ColdFusion doesn't play nicely with varargs
I found a workaround using this method
https://www.bennadel.com/blog/1980-tojava---a-coldfusion-user-defined-function-for-complex-java-casting.htm
I believe there is a bug with Javacast and javaSettings loadPaths not being used.
coldfusion.runtime.Cast$UnknownTypeException: Cannot convert the value
to Java array because type org.elasticsearch.client.Node is unknown.
at coldfusion.runtime.Cast.toJavaArray(Cast.java:1602)
Additionally if I try to perform the actiuons that the UDF takes
local.javaClass = createObject("java", "org.apache.http.HttpHost");
local.HostArrayReflect = createObject("java", "java.lang.reflect.Array");
local.HostArray = local.HostArrayReflect.newInstance(
local.javaClass.GetClass()
, JavaCast( "int", ArrayLen(local.Hosts))
);
for (i=0; i LT ArrayLen(local.Hosts); i=i+1) {
local.HostArrayReflect.Set(local.HostArray, JavaCast("int", i), local.Hosts[i]);
}
I get the error
An exception occurred while instantiating a Java object. The class
must not be an interface or an abstract class. If the class has a
constructor that accepts an argument, you must call the constructor
explicitly using the init(args) method. Error :
org.apache.http.HttpHost
java.lang.NoSuchMethodException: org.apache.http.HttpHost.() at
java.lang.Class.getConstructor0(Class.java:3082) at
java.lang.Class.newInstance(Class.java:412) at
coldfusion.runtime.java.JavaProxy.createObjectWithDefaultConstructor(JavaProxy.java:209)
at coldfusion.runtime.java.JavaProxy.invoke(JavaProxy.java:92)
This happens when I try to run getClass(), but in the UDF there is no issue. A coworker tried to run this on Lucee and it seems to have worked, so I believe there is a bug in CF related to this.
Executing the following code in Java7
ScriptEngine scriptEngine = new ScriptEngineManager().getEngineByName("js");
Bindings b = scriptEngine.createBindings();
b.put("x", true);
scriptEngine.eval("x&y", b);
I get the error
sun.org.mozilla.javascript.internal.EcmaError: ReferenceError: "b" is not defined. (<Unknown Source>#1) in <Unknown Source> at line number 1
Is there an option to evaluate to null/false for undefined objects, like in JavaScript?
I know that an option will be to do something like "this.x&this.y" instead of "x&y", but I don't have control over that string (user entered).
I browsed a little bit through the Rhino code and it seems that there's no such option.
In the end I will append "this." in front of each variable. This is not by far a desirable solution (I will not even accept my own answer :) ), but for the time being I have no other.
In both the Joy of Clojure and on Alex Miller's Pure Danger Tech blog-post it is recommended that you can print the last stack using something like the following:
(use 'clojure.stacktrace)
(java.util.Date. "foo")
(.printStackTrace *e 5)
But I can't get any of their examples to work, and instead just get
java.lang.NullPointerException: null
Reflector.java:26 clojure.lang.Reflector.invokeInstanceMethod
(Unknown Source) jtown$eval9755.invoke
What's up with this? .printStackTrace seems to be a Java function from the looks of it, so I am not sure why I am bringing clojure.stacktrace into my namespace, in the first place. I read through the clojure.stacktrace API, though, and see an e function, which seems similar too but is not the *e function, which is in core and is supposed to be binding to the last exception, but isn't. Could somebody straighten me out on the best way to check stack-traces?
There are some special vars available when using the REPL and
*e - holds the result of the last exception.
For instance:
core=> (java.util.Date. "foo")
IllegalArgumentException java.util.Date.parse (Date.java:615)
core=> (class *e)
java.lang.IllegalArgumentException
core=> (.printStackTrace *e)
java.lang.IllegalArgumentException
at java.util.Date.parse(Date.java:615)
<not included.....>
You are right, .printStackTrace is the java method that is invoked on the exception class. This is not very straightforward (since its java interop) so clojure.stacktrace namespace has some utilities about working with stack traces
So after
(use 'clojure.stacktrace)
you can use the stacktrace library instead of java interop:
core=> (print-stack-trace *e)
java.lang.IllegalArgumentException: null
at java.util.Date.parse (Date.java:615)
<not included.....>
Obviously in an app, instead of *e, you can do a try - catch and use the related functions as necessary
I use
(.printStackTrace *e *out*)
That seems to work.
I'm trying to add new keys in application.conf file in play framework 2.1. I have added the following keys:
gen.db.host=localhost
gen.db.port=27017
gen.db.name=test
When i start my application, it is throwing the following error:
Configuration error: Configuration error[application.conf: 46: port has type NUMBER rather than OBJECT]
......
......
......
Caused by: com.typesafe.config.ConfigException$WrongType: application.conf: 46: port has type NUMBER rather than OBJECT
I don't understand this issue. How can i resolve it? Also, is it a good practice to define new keys in application.conf file?
Thanks.
Put the port between double quotes:
gen.db.port="27017"
You have to use a colon
gen.dn.port:"26017"
Here's a link to the current documentation
http://www.playframework.com/documentation/2.0.x/Configuration
You are propably using wrong method to extract the data from config. I assume you use it like:
current.configuration.getConfig("gen.db.port")
But this method returns play.api.Configuration and expects an object to be under the path "gen.db.port" (as it is mentioned in the error). Since under the "gen.db.port" path you have a number, you should change the method to:
current.configuration.getNumber("gen.db.port")
I'm trying to use Java Opencl from within jruby, but am encountering a problem which I can't solve, even with much google searching.
require 'java'
require 'JOCL-0.1.7.jar'
platforms = org.jocl.cl_platform_id.new
puts platforms.class
org.jocl.CL.clGetPlatformIDs(1, platforms, nil)
when I run this code using: jruby test.rb
I get the following error, when the last line is uncommented:
#<Class:0x10191777e>
TypeError: cannot convert instance of class org.jruby.java.proxies.ConcreteJavaP
roxy to class [Lorg.jocl.cl_platform_id;
LukeTest at test.rb:29
(root) at test.rb:4
Just wondering whether anyone has an idea on how to solve this problem?
EDIT:
ok so I think I've solved the first part of this problem by making platforms an array:
platforms = org.jocl.cl_platform_id[1].new
but that led to this error when adding the next couple of lines:
context_properties = org.jocl.cl_context_properties.new()
context_properties.addProperty(org.jocl.CL::CL_CONTEXT_PLATFORM, platforms[0])
CodegenUtils.java:98:in `human': java.lang.NullPointerException
from CodegenUtils.java:152:in `prettyParams'
from CallableSelector.java:462:in `argumentError'
from CallableSelector.java:436:in `argTypesDoNotMatch'
from RubyToJavaInvoker.java:248:in `findCallableArityTwo'
from InstanceMethodInvoker.java:66:in `call'
from CachingCallSite.java:332:in `cacheAndCall'
from CachingCallSite.java:203:in `call'
from test.rb:36:in `module__0$RUBY$LukeTest'
from test.rb:-1:in `module__0$RUBY$LukeTest'
from test.rb:4:in `__file__'
from test.rb:-1:in `load'
from Ruby.java:679:in `runScript'
from Ruby.java:672:in `runScript'
from Ruby.java:579:in `runNormally'
from Ruby.java:428:in `runFromMain'
from Main.java:278:in `doRunFromMain'
from Main.java:198:in `internalRun'
from Main.java:164:in `run'
from Main.java:148:in `run'
from Main.java:128:in `main'
for some reason when I print the class of platforms[0] it's listed as NilClass!?
You are overlooking a very simple mistake. You write
platforms = org.jocl.cl_platform_id.new
but that line creates a single instance of the class org.jocl.cl_platform_id. You then pass that as the second parameter to org.jocl.CL.clGetPlatformIDs in
org.jocl.CL.clGetPlatformIDs(1, platforms, nil)
and that doesn't work, because the second argument of the method requires an (empty) array of org.jocl.cl_platform_id objects.
What the error says is: "I have something that is a proxy for a Java object and I can't turn it into an an array of org.jocl.cl_platform_id objects, as you are asking me to do.
If you just say
platforms = []
and pass that in, it might just work :).