I'm writing node.js bindings and I want to generate JSON string from v8::Object instances. I want to do it in C++. Since node.js already has JSON.stringify, I would like to use it. But I don't know how to access it from the C++ code.
You need to grab a reference to the global object, and then grab the stringify method;
Local<Object> obj = ... // Thing to stringify
// Get the global object.
// Same as using 'global' in Node
Local<Object> global = Context::GetCurrent()->Global();
// Get JSON
// Same as using 'global.JSON'
Local<Object> JSON = Local<Object>::Cast(
global->Get(String::New("JSON")));
// Get stringify
// Same as using 'global.JSON.stringify'
Local<Function> stringify = Local<Function>::Cast(
JSON->Get(String::New("stringify")));
// Stringify the object
// Same as using 'global.JSON.stringify.apply(global.JSON, [ obj ])
Local<Value> args[] = { obj };
Local<String> result = Local<String>::Cast(stringify->Call(JSON, 1, args));
Some of the node API's have changed from the publishing of the OP. Assuming a node.js version 7.7.1, the code transforms to something along the lines of;
std::string ToJson(v8::Local<v8::Value> obj)
{
if (obj.IsEmpty())
return std::string();
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::HandleScope scope(isolate);
v8::Local<v8::Object> JSON = isolate->GetCurrentContext()->
Global()->Get(v8::String::NewFromUtf8(isolate, "JSON"))->ToObject();
v8::Local<v8::Function> stringify = JSON->Get(
v8::String::NewFromUtf8(isolate, "stringify")).As<v8::Function>();
v8::Local<v8::Value> args[] = { obj };
// to "pretty print" use the arguments below instead...
//v8::Local<v8::Value> args[] = { obj, v8::Null(isolate), v8::Integer::New(isolate, 2) };
v8::Local<v8::Value> const result = stringify->Call(JSON,
std::size(args), args);
v8::String::Utf8Value const json(result);
return std::string(*json);
}
Basically, the code gets the JSON object from the engine, obtains a reference to the function stringify of that object, and then calls it. The code is tantamount to the javascript;
var j = JSON.stringify(obj);
Further v8 based alternatives include using the JSON class.
auto str = v8::JSON::Stringify(v8::Isolate::GetCurrent()->GetCurrentContext(), obj).ToLocalChecked();
v8::String::Utf8Value json{ str };
return std::string(*json);
Related
I have a C++ object which inherits from node::ObjectWrap. The object itself manages the resource so it accepts it as an argument in a private constructor.
When object is created from Javascript it's quite straightforward:
void New(const v8::FunctionCallbackInfo<v8::Value>& args) {
// ...
auto handleToCustomResource = resolveFromJSArg(args[0]->ToString());
auto object = new MyObjectWrap(handleToCustomResource);
object->Wrap(args.This());
args.GetReturnValue().Set(args.This());
}
However it's not clear how to wrap the object when it originates from C++, here is my recent effort:
public v8::Local<v8::Object> CreateObject(v8::Isolate *isolate, const char *name) {
v8::Local<v8::Context> context = isolate->GetCurrentContext();
v8::EscapableHandleScope scope(isolate);
auto object = new MyObjectWrap(handleToMyCustomResource);
v8::Local<v8::Object> instance = // eh don't have an instance??
object->Wrap(instance);
return scope.Escape(instance);
}
How to properly create a JS object so I could use it as an instance for my native object?
One of workarounds I found is to basically have two constructors, one public and one private and then inherit one from another. The public one is available in javascript, while the private is solely used to create an instance for wrapping an existing ObjectWrap object.
v8::Local<v8::FunctionTemplate> privTpl = v8::FunctionTemplate::New(isolate, PrivateNew);
v8::Local<v8::FunctionTemplate> pubTpl = v8::FunctionTemplate::New(isolate, New);
// define prototype
pubTpl->Inherit(privTpl);
exports->Set(v8::String::NewFromUtf8(isolate, "MyObject"), tpl->GetFunction());
We are trying to embed several Python procedures in our C++ code using and it fails with an error
TypeError: No to_python (by_value) converter found for C++ type: boost::python::detail::kwds_proxy
We honestly studied all the examples we managed to find over the network (this and this), but still we have no any clear solution for passing the ****kwargs** variable from C++ to Python. This failure seems to be very rare.
Python function we are trying to call recieves a string value and a dictionary:
from ipalib import api
user_kw = dict(givenname=u'Test', sn=u'User')
api.Command.user_add.(u'Pythonist', **user_kw)
This is its C++ implementation:
//Importing modules
bp::import("__main__");
ipalib = bp::import("ipalib");
ipalib_namespace = ipalib.attr("__dict__");
api = ipalib.attr("api");
... //Starting Python environment
//Construct args
std::string name = "Pythonist";
bp::dict new_user;
new_user["givenname"] = "Test";
new_user["sn"] = "User";
//Calling the function
bp::object user_add_wrapper = api.attr("Command").attr("user_add");
user_add_wrapper(name, new_user);
And on the last line Boost throws an exception. What are we doing wrong? Thank you.
user_add_wrapper(name, new_user) tries to pass new_user as a dictionary to user_add_wrapper(), rather than passing the unpacked contents of new_user. The new_user dictionary needs to be unpacked. Additionally, calling the python::object with an unpacked dictionary requires the first argument to be an unpacked boost::python::tuple. To account for these requirements, invoke user_add_wrapper() as follows:
user_add_wrapper(*bp::make_tuple(name), **new_user);
This behavior is part of the seamless interoperability provided by Boost.Python, but it is rather obscure and I only recall noticing it mentioned indirectly in the change log rather than the tutorial or reference.
Below is a complete minimal example. Given example.py:
def user_add(name, givenname, sn):
print locals()
The following program invokes user_add() by unpacking a dictionary:
#include <boost/python.hpp>
int main()
{
Py_Initialize(); // Start interpreter.
// Create the __main__ module.
namespace python = boost::python;
python::object main = python::import("__main__");
python::object main_namespace = main.attr("__dict__");
try
{
python::object example = python::import("example");
python::object example_namespace = example.attr("__dict__");
// Construct args.
std::string name = "Pythonist";
python::dict new_user;
new_user["givenname"] = "Test";
new_user["sn"] = "User";
// Invoke user_add by unpacking the new_user dictionary.
example_namespace["user_add"](*python::make_tuple(name), **new_user);
}
catch (const python::error_already_set&)
{
PyErr_Print();
}
}
And produces the following output:
{'givenname': 'Test', 'sn': 'User', 'name': 'Pythonist'}
In a play framework 1.2.4 Controller, is it possible to get the contents of a template or tag as a String before output to the browser?
I want to be able to do this:
String json = renderAsString("/path/to/template.json", var1, var2);
//then use json as the body of a Play.WS request body.
The solution is based on the assumption that you are talking about PlayFramework 1.x
If you are using Groovy template engine:
Map<String, Object> args = ...
Template template = TemplateLoader.load("path/to/template.suffix");
String s = template.render(args);
And you have a shortcut way if you are using Rythm template engine:
String s = Rythm.render("path/to/template.suffix", param1, param3...);
Or you can also use named arguments:
Map<String, Object> args = ...
String s = Rythm.render("path/to/template.suffix", args);
Note the Groovy way also works for Rythm if your template file is put under app/rythm folder.
In addition to green answer.
If creating a json is what you want you would better use gson rather than building your own string with groovy templates. Gson is included in Play Framework 1.2.X.
You can find more information here. Example from Gson doc:
class BagOfPrimitives {
private int value1 = 1;
private String value2 = "abc";
BagOfPrimitives() {
// no-args constructor
}
}
BagOfPrimitives obj = new BagOfPrimitives();
Gson gson = new Gson();
String json = gson.toJson(obj);
//json is {"value1":1,"value2":"abc"}
You can also use Flexjson instead of gson.
I'm writing Agueas [1] addon for Node.js
For now I have synchronous code, C++ class looks like this:
class LibAugeas : public node::ObjectWrap {
public:
static void Init(Handle<Object> target);
protected:
augeas * m_aug;
LibAugeas();
~LibAugeas();
static Handle<Value> New(const Arguments& args);
static Handle<Value> get (const Arguments& args);
static Handle<Value> set (const Arguments& args);
static Handle<Value> setm (const Arguments& args);
// other methods
};
Usage of this class in JS:
var lib = require('...');
var aug = new lib.Augeas(...);
aug.set(...);
aug.get(...);
// etc
I'm going to impelement asynchronous code.
The bottleneck is creating augeas object (aug_init) while all or some lenses and files are being loaded and parsed. So the idea is creating augeas object asynchronously, and then pass created JS object in a callback function:
Pure C thread: call aug_init(), aug_load() to get augeas handle.
When ready, use augeas handle to creat JS object (see the first snippet)
Pass created JS object to callback function.
Usage might be as such:
lib.heracles(function(aug) {
if (!aug.error()) {
console.log('Hello!');
// async save:
aug.save(function(err, msg) {
console.log(msg);
});
} else {
console.log('Sad, but true :-(');
}
}
);
And finally, my problem: I do not know how to create JS object in C++ :-)
Constructor static Handle<Value> New(const Arguments& args); returns args.This(), but when I'm in C++ code I do not have args and also can't wrap object.
So, how do I create JS object in C++? Please, don't break my heart saying it is not possible :-)
[1] http://augeas.net
Ok, thanks to everyone :-)
I've found the right way. Here is a static method which creates an JS object wrapping given augeas handle.
Then I can pass this object to callback function from C++ code.
Local<Object> LibAugeas::New(augeas *aug)
{
LibAugeas *obj = new LibAugeas();
obj->m_aug = aug;
Handle<ObjectTemplate> tpl = ObjectTemplate::New();
tpl->SetInternalFieldCount(1); // one field for LibAugeas* pointer (via obj->Wrap())
#define _OBJ_NEW_METHOD(m) NODE_SET_METHOD(tpl, #m, m)
_OBJ_NEW_METHOD(get);
_OBJ_NEW_METHOD(set);
_OBJ_NEW_METHOD(setm);
_OBJ_NEW_METHOD(rm);
_OBJ_NEW_METHOD(mv);
_OBJ_NEW_METHOD(save);
_OBJ_NEW_METHOD(nmatch);
_OBJ_NEW_METHOD(insert);
_OBJ_NEW_METHOD(error);
Local<Object> O = tpl->NewInstance();
obj->Wrap(O);
return O;
}
I use node.js for a while, now I need write an add-on, but I am a newb of c++.
in node.js I can pass optional arguments to function, and check their types.
function hello(arg, options, callback){
if(!callback){
if(typeof options === 'function'){
callback = options;
options = {};
}
}
console.log(typeof arg);
}
But in an addon.
Handle<Value> hello(const Arguments &args) {
HandleScope scope;
printf("%d\n", args.Length());
// how to check type of args[i]
return String::New("world");
}
You should look over the API in http://v8.googlecode.com/svn/trunk/include/v8.h. Most of the functions you are interested are on the Value class. There is documentation online here, http://bespin.cz/~ondras/html/classv8_1_1Value.html but that looks like just some random person's uploaded version of the docs. Not sure if they are online somewhere else.
Something like this should do about the same thing as your JS snippet.
Handle<Value> hello(const Arguments &args) {
HandleScope scope;
Local<Value> arg(args[0]);
Local<Value> options(args[1]);
Local<Value> callback(args[2]);
if (callback.equals(False())) {
if (options->IsFunction()) {
callback = options;
options = Object::New();
}
}
// ...
}