Java code migration error using com.jayway.jsonpath.JsonPath - coldfusion

I am using Java code and converting the code in ColdFusion. There are some challenges where I am stuck. This is one function I have in Java:
import com.jayway.jsonpath.JsonPath;
import net.minidev.json.JSONArray;
import net.minidev.json.JSONStyle;
private static String getDetails(String instaDetailsElement) {
String jsonResponse = instaDetailsElement.split(" = ")[1];
JSONArray mediaArray = JsonPath.read(jsonResponse, "$.entry_data.PostPage[:1].graphql.shortcode_media");
String returnJsonString = mediaArray.toJSONString(new JSONStyle(JSONStyle.FLAG_IGNORE_NULL));
System.out.println(returnJsonString);
return returnJsonString;
}
These two lines are giving me some trouble:
var mediaArray = JsonPath.read(jsonResponse, "$.entry_data.PostPage[:1].graphql.shortcode_media");
var returnJsonString = mediaArray.toJSONString(new JSONStyle(JSONStyle.FLAG_IGNORE_NULL));
Here is what I attempted so far. I loaded the jar library for JSON path and tried using it like this:
Application.cfc settings
<cfset this.javaSettings = {LoadPaths = ["cfc/jar"], loadColdFusionClassPath = true, reloadOnChange = false}>
CF Code:
public any function getDetails(String instaDetailsElement) {
var jsonResponse = instaDetailsElement.split(" = ")[1];
var JsonPath = Createobject("java","com.jayway.jsonpath.JsonPath");
writedump(application);
var mediaArray = JsonPath.read(jsonResponse, "$.entry_data.PostPage[:1].graphql.shortcode_media");
writedump(mediaArray); abort;
var returnJsonString = mediaArray.toJSONString(new JSONStyle(JSONStyle.FLAG_IGNORE_NULL));
return returnJsonString;
}
I'm able to view the class methods when I dump the JsonPath object (screen shot), but when I try to call JsonPath.read() I get this error:
No matching Method for read(string, string) found for
com.jayway.jsonpath.JsonPath

TL;DR;
No matching method for read(string, string) found for com.jayway.jsonpath.JsonPath
Technically the error message is correct: there is no read() method that accepts two strings (even though that's how it's used in the java code). The method actually expects three arguments:
Pass in an empty array for the 3rd argument:
JsonPath.read(jsonResponse, "$.entry_data.PostPage[:1].graphql.shortcode_media", []);
Explanation:
String jsonResponse = instaDetailsElement.split(" = ")[1];
JsonPath.read(jsonResponse, "$.entry_data.PostPage[:1].graphql.shortcode_media")
If there really is no read(String, String) method, you might wonder why the java code works at all, since that's exactly what it uses. It works due to a special feature of java.
The documentation shows the overloaded read(..) method actually has three parameters, but one of them is special:
read(String json,
String jsonPath,
Predicate... filters)
Notice the ... after the class name (Predicate)? It's a construct called "varargs" (or variable number of arguments):
You can use a construct called varargs to pass an arbitrary number of values to a method. You use varargs when you don't know how many of a
particular type of argument will be passed to the method. It's a
shortcut to creating an array manually ...
To use varargs, you follow the type of the last parameter by an ellipsis (three dots, ...), then a space, and the parameter name. The
method can then be called with any number of that parameter,
including none.
So in java you're allowed to omit the third argument entirely and call read(String, String) with two strings. ColdFusion doesn't support that syntax, because it creates too much ambiguity. So in lieu of omitting the argument, you can pass in an empty array instead:
JsonPath.read(jsonResponse, "$.entry_data.PostPage[:1].graphql.shortcode_media", []);

(Since this has turned into two questions in one thread, I'm separating the second answer out for clarity ...)
var returnJsonString = mediaArray.toJSONString(new JSONStyle(JSONStyle.FLAG_IGNORE_NULL));
As for translating the JSONStyle code, it helps to unpack nested code from the inside out. Then tackle each piece separately:
mediaArray.toJSONString(new JSONStyle( JSONStyle.FLAG_IGNORE_NULL ));
mediaArray.toJSONString( new JSONStyle( JSONStyle.FLAG_IGNORE_NULL ) )
mediaArray.toJSONString( new JSONStyle( JSONStyle.FLAG_IGNORE_NULL ) )
Piece #1
Uses a static field of the JSONStyle class named FLAG_IGNORE_NULL. To access the field, create a reference to that class:
JsonStyle = createObject("java", "net.minidev.json.JSONStyle");
writeDump(JSONStyle.FLAG_IGNORE_NULL);
Piece #2
Creates a brand new instance of the JSONStyle class, using the static field from above. Use createObject() to create the new instance, passing the static field into the psuedo constructor init():
newJsonStyle = createObject("java", "net.minidev.json.JSONStyle").init(JSONStyle.FLAG_IGNORE_NULL);
writeDump( newJsonStyle );
Piece #3
All that's left is calling the JSONArray.toJSONString() method with the JSONStyle object you just created:
result = mediaArray.toJSONString( newJsonStyle );
writeDump(result);

Related

Configuring C# out parameters with Foq in F#

I am using F# and Foq to write unit tests for a C# project.
I am trying to set up a mock of an interface whose method has an out parameter, and I have no idea how to even start. It probably has to do with code quotations, but that's where my understanding ends.
The interface is this:
public interface IGetTypeNameString
{
bool For(Type type, out string typeName);
}
In C# Foq usage for the interface looks like this:
[Fact]
public void Foq_Out()
{
// Arrange
var name = "result";
var instance = new Mock<IGetTypeNameString>()
.Setup(x => x.For(It.IsAny<Type>(), out name))
.Returns(true)
.Create();
// Act
string resultName;
var result = instance.For(typeof(string), out resultName);
// Assert
Assert.True(result);
Assert.Equal("result", resultName);
}
As for how to achieve that with F#, I am completely lost. I tried something along the lines of
let name = "result"
let instance = Mock<IGetTypeNameString>().Setup(<# x.For(It.IsAny<Type>(), name) #>).Returns(true).Create();
which results in the quotation expression being underlined with an error message of
This expression was expected to have type IGetTypeNameString -> Quotations.Expr<'a> but here has type Quotations.Expr<'b>
Without any indication what types a and b are supposed to be, I have no clue how to correct this.
:?>
(It gets even wilder when I use open Foq.Linq; then the Error List window starts telling me about possible overloads with stuff like Action<'TAbstract> -> ActionBuilder<'TAbstract>, and I get even loster....)
Any assistance or explanation greatly appreciated!
Edit:
So, as stated here, byref/out parameters can not be used in code quotations. Can this be set up at all then in F#?
Foq supports setting up of C# out parameters from C# using the Foq.Linq namespace.
The IGetTypeNameString interface can be easily setup in F# via an object expression:
let mock =
{ new IGetTypeNameString with
member __.For(t,name) =
name <- "Name"
true
}
For declarations that have no analog in F#, like C#'s protected members and out parameters, you can also use the SetupByName overload, i.e.:
let mock =
Mock<IGetTypeNameString>()
.SetupByName("For").Returns(true)
.Create()
let success, _ = mock.For(typeof<int>)

CF10 Twitter4j lookupUsers method was not found or method is overloaded

I am using CFML and Twitter4j to return timelines and lists.
I want to return the data from a call to lookupUsers(java.lang.String[] screenNames)
via Twitter4j.
I have tried the :-
strList = createObject("java", "java.util.ArrayList");
strList.add(strOriginUser);
originUser = t4j.lookupUsers(strList);
And :-
strUserString = JavaCast("String", strOriginUser);
originUser = t4j.lookupUsers(strUserString);
I know the t4j Object is working as I already use it to get timelines etc but here it is for completeness :-
public function init_twitter() {
//CONFIGURE twitter4j
configBuilder = createObject("java", "twitter4j.conf.ConfigurationBuilder");
configBuilder.setOAuthConsumerKey(#application.twitter_consumer_key#);
configBuilder.setOAuthConsumerSecret(#application.twitter_consumer_secret#);
configBuilder.setOAuthAccessToken(#application.twitter_access_token#);
configBuilder.setOAuthAccessTokenSecret(#application.twitter_access_token_secret#);
configBuilder.setIncludeEntitiesEnabled(true);
configBuilder.setJSONStoreEnabled(true);
config = configBuilder.build();
twitterFactory = createObject("java", "twitter4j.TwitterFactory").init(config);
variables.t4j = twitterFactory.getInstance();
return this;
}
The twitter4j documentations is:-
ResponseList<User> lookupUsers(java.lang.String[] screenNames) throws TwitterException
Return up to 100 users worth of extended information, specified by either ID, screen name, or combination of the two. The author's most recent status (if the authenticating user has permission) will be returned inline.
This method calls http://api.twitter.com/1.1/users/lookup.json
Parameters:
screenNames - Specifies the screen names of the users to return.
Returns:
users
It looks like you are trying to pass an ArrayList object into lookupUsers but that method only accepts String[] (an array of Strings) as an argument. So unless CFML does the conversion, I don't think it's going to work.
From a cursory glance at the ColdFusion docs, it looks like CFML can implicitly convert a CFML Array to a Java array, so perhaps the following would work:
screenNames = arrayNew(1);
screenNames[1] = 'Fry';
originUser = t4j.lookupUsers(screenNames);
Alternatively, if you want to keep on using a list there is an ArrayList#toArray(T[]) which could be useful, although I can't say how useful that would be in the CFML.
N.B. Please excuse my CFML code snippet.

Python C API - Creating keywords

I'm running into trouble trying to call a Python function from my C++ code.
I'm trying to call the Django function call_command, with the following parameters:
call_command('test', stdout=content)
See here why. This runs the command without the stdout=content argument:
PyObject_CallFunctionObjArgs(executeFunc, PyString_FromString("test"), NULL)
I can't, for the life of me, figure out how to create this keyword.
PyDict_New();
PyDict_SetItemString(...);
Nets me a 'stdout'='content' string, instead of stdout=content.
Py_BuildValue("{s=s}", ... , ...)
Does the same thing.
I can get the content PyObject no problem if necessary, I just can't seem to correctly create the stdout keyword argument without Python putting quotes (handling it as a string) at some point.
How can I call call_command('test', stdout=content) from the C API?
PyObject *args = Py_BuildValue("(s)", "test");
PyObject *kwargs = PyBuildValue("{s:O}", "stdout", content);
PyObject_Call(executeFunc, args, kwargs);
Note that even in Python, you can call the function the same way:
args = ("test",)
kwargs = {"stdout" : content}
call_command(*args,**kwargs)
"stdout" is a string with quotes here too, but it works. You are trying to get the same syntax as you use in Python, with noquotename=noquotevalue, but the syntax is just a representation. Both {"quotedname" : noquotevalue} and noquotename=noquotevalue are two different ways to represent the same thing. They both actually represent a dictionary whose key is a string and value is an object. That is what you pass as the third argument to PyObject_Call.
Py_BuildValue("{s:O}", "stdout", content_obj)

Inspect Ember.js: Get the type of an object (Class)?

I use console.log() a lot, especially in combination with Ember.inspect(). But there's one thing I miss:
How can I find out the type of an object (Class)?
For example: Getting something like <Sandbox.ApplicationController:ember288> when inspecting Ember.get("controller")?
If you just want the model name (for example app/models/comment.js has the model name comment), you can use thing.constructor.modelName.
For example:
var aComment = this.get('store').createRecord('comment');
aComment.get('constructor.modelName') // => 'comment'
I understand you are looking for a string for debugging purposes, but I originally came to this question wanting to know specifically how to get the type of the object, not a string describing the object.
Using the built in Javascript property constructor will yield the class used to construct the instance. For example you could do:
person = App.Person.create();
person.constructor // returns App.Person
person.constructor.toString() // return "App.Person"
If you get Class, you can usually call toString() (or as a shortcut concat an empty string + '') to get something like <Sandbox.ApplicationController:ember288>
Another useful feature (in chrome) is the dir command.
dir(App.User)
This will give you the full object information, rather than just the name.
Be aware that some of these answers suggested here only work in development. Once your code is in production most of those methods / class names will get minified.
import Model from '#ember-data/model';
export default class Animal extends Model {
// ...
}
So in development:
const model = this.store.createRecord('animal');
model.constructor.name // returns Animal
in production:
const model = this.store.createRecord('animal');
model.constructor.name // returns 'i' (or any other single letter).
To avoid this, use constructor.toString()
const model = this.store.createRecord('animal');
model.constructor.toString() // returns 'model:animal'

ColdFusion 9 Dynamic Method Call

I am trying to work out the correct <cfscript> syntax for calling a dynamic method within ColdFusion 9. I have tried a number of variations and had a good search around.
<cfinvoke> is clearly the tag I want, sadly however I cannot use this within my pure cfscript component as it was implemented in ColdFusion 10.
i.e coldfusion 9 dynamically call method
I have tried the following within my CFC:
/** Validate the method name **/
var resources = getResources();
if (structKeyExists(variables.resources, name)) {
variables.resourceActive[name] = true;
var reflectionMethod = resources[name];
var result = "#reflectionMethod.getMethodName()#"(argumentCollection = params);
}
Where the return value of reflectionMethod.getMethodName() is the method name I want to call. It is 100% returning the correct value (the name of the method) where that method is correctly defined and accessible,
My error is a syntax error on that line.
You don't want to get the method name, you want to get the actual method, eg something like:
function getMethod(string method){
return variables[method];
}
The call that, thus:
theMethod = getMethod(variableHoldingMethodName);
result = theMethod();
Unfortunately one cannot simply do this:
result = getMethod(variableFoldingMethodName)();
Or:
result = myObject[variableFoldingMethodName]();
As the CF parser doesn't like the double-up of the parentheses or brackets.
The caveat with the method I suggested is that it pulls the method out of the CFC, so it will be running in the context of the calling code, not the CFC instance. Depending on the code in the method, this might or might not matter.
Another alternative is to inject a statically-named method INTO the object, eg:
dynamicName = "foo"; // for example
myObject.staticName = myObject[dynamicName];
result = myObject.staticName(); // is actually calling foo();
Assuming the method is in your current (variables) scope, you could try:
var result = variables[reflectionMethod.getMethodName()](argumentCollection = params);