What is a PoliglotMap in GraalVM? - javascript

I am working with the org.graalvm.polyglot script engine in my Java11 project to evaluate a JavaScript.
The script to be evaluated returns a JavaScript array with two entries.
...
var result={};
result.isValid=false;
result.errorMessage = new Array();
result.errorMessage[0]='Somehing go wrong!';
result.errorMessage[1]='Somehingelse go wrong!';
....
In my java code I try to evaluate the result object:
Value resultValue = context.getBindings(languageId).getMember("result");
In my Eclipse Debugger I can see that I receive a PolyglotMap containing the expected values:
I can iterate over that map to get the values with a code like this:
...
try {
mapResult = resultValue.as(Map.class);
} catch (ClassCastException | IllegalStateException | PolyglotException e) {
logger.warning("Unable to convert result object");
return null;
}
Iterator it = mapResult.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pair = (Map.Entry) it.next();
String itemName = pair.getKey().toString();
Object itemObject = pair.getValue();
...
In this way I am able to extract the boolean 'isValid'. But with the object 'errorMessage' I struggle.
Inspecting the Object again within the Eclipse Debugger it looks like this:
If I test this object it is an instanceOf Map. But I am unable to get any of the values out of this object.
Can anybody help me to understand what exactly this object represents and how I can extract the both values 'Someting go wrong!' and 'Sometingelse go wrong!' ?
When I iterate over this second map it seems to be empty - even if the debugger shows me the correct values.

I'm not 100% sure why as(Map.class) behaves that way, it might be worth creating an issue on github to figure it out: github.com/oracle/graal
But if you access the values using the API without converting to a Map it would work as you expect:
var errorMessage = resultValue.getMember("errorMessage");
errorMessage.hasArrayElements(); // true
var _0th = errorMessage.getArrayElement(0);
var _1th = errorMessage.getArrayElement(1);
You can also convert the polyglotMap to Value and then do it:
val errorMessage = context.asValue(itemObject);
errorMessage.hasArrayElements(); // true
errorMessage.getArrayElement(0);
PolyglotMap of course has the get method. And the Value javadoc says that:
Map.class is supported if the value has Value.hasHashEntries() hash entries}, members or array elements. The returned map can be safely cast to Map. For value with members the key type is String. For value with array elements the key type is Long.
Can you try getting them with the Long keys?
There might be something obvious I'm missing, so in any case it's better to raise an issue on GitHub.

Related

sessionStorage.setItem with JSON.stringify causes javascript function to fail

I am storing two items in sessionStorage, an integer and a string array. I can see the items in Chrome Dev Console (Application - sessionStorage) and they are correct.
The values as it shows now in the Chrome Dev Console are:
HTTP_Index 4
HTTP_History ["Start","text_14","text_7","text_10"]
In a javascript function, I retrieve them from sessionStorage:
var HTTP_Index = sessionStorage.getItem(HTTP_Index);
var HTTP_History = sessionStorage.getItem(HTTP_History);
p_Index = JSON.parse(HTTP_Index);
p_History = JSON.parse(HTTP_History);
I decrement the index:
p_Index = p_Index - 1;
console.log("HTTP_Index Now " + p_Index);
and the log shows that the value is now 3.
Next I store the value p_Index back to sessionStorage:
sessionStorage.setItem("HTTP_Index", JSON.stringify({ "p_Index" });
Whether I enclose p_Index in quotes or not, the dev console now shows the function as "undefined."
Next I tried to do it like this:
sessionStorage.setItem("HTTP_Index", JSON.stringify({ "p_Index" });
but same problem. So finally I tried this:
var obj = { HTTP_Index: p_Index };
var objJSON = JSON.stringify(obj);
sessionStorage.setItem(objJSON);
But the Chrome dev console shows:
Uncaught TypeError: Failed to execute 'setItem' on 'Storage': 2 arguments required, but only 1 present.
What am I doing wrong in using JSON.stringify for sessionStorage.setItem?
Thanks for any help.
When using .setItem you must set a key, and then the value you want to store.
In the case of your first example, you're doing this but have made a simple typo. Also you want to stringify the contents in p_Index, not the string "p_index", so, you need to remove your quotes around it when stringifying:
sessionStorage.setItem("HTTP_Index", JSON.stringify(p_Index)); // <-- missing this closing bracket
And so you'll get a syntax error here.
In the case of your second example (attempt), you're not using valid syntax as you're setting an object with no value.
In your third example, you're trying to set the value to be the stringified object (so your value is just the string, not the object), and so you're not specifying a key. To do this you can use:
var objJSON = JSON.stringify(p_index);
sessionStorage.setItem("HTTP_Index", objJSON);
In your latest example:
var obj = { HTTP_Index: p_Index };
var objJSON = JSON.stringify(obj);
sessionStorage.setItem(objJSON);
sessionStorage.setItem first argument must be the key which you want to set and the 2nd is the data which you are going to store.
So you miss the key/name.

Trying to get the"name" of a javascript object supplied by an API

I am calling an API which is giving me back, among other things, an array of javascript objects. The objects in the array are named and I need to use the name in the new individual objects I am creating from the array. Problem is, I don't know how to get to the object's name.
{
"OldCrowMine.E9001":{"last_share":1524883404,"score":"0.0","alive":false,"shares":0,"hashrate":0},
"OldCrowMine.S9001":{"last_share":1524,"score":"648.24","alive":true,"shares":632,"hashrate":14317274},
}
I am after the "OldCrowMine.E9001" bit. I am sure this is quite simple, I just don't know how to search for the answer because I am not sure what to call this. I have tried searching for a solution.
Just loop - or am I missing something? Simplified raw data version.
var raw = {
"OldCrowMine.E9001":{"share":1524883404},
"OldCrowMine.S9001":{"share":1524}
};
for(var first in raw) {
console.log(first +" share -> "+ raw[first]["share"]);
}
var obj = {
"OldCrowMine.E9001":{"last_share":1524883404,"score":"0.0","alive":false,"shares":0,"hashrate":0},
"OldCrowMine.S9001":{"last_share":1524,"score":"648.24","alive":true,"shares":632,"hashrate":14317274},
}
console.log(Object.keys(obj)[0]);
Get the keys and map the name and the object:
var x= {
"OldCrowMine.E9001":{"last_share":1524883404,"score":"0.0","alive":false,"shares":0,"hashrate":0},
"OldCrowMine.S9001":{"last_share":1524,"score":"648.24","alive":true,"shares":632,"hashrate":14317274},
};
var mapped = Object.keys(x).map(function(d,i){return [d,x[d]]});
The name is map[n][0] and its object is map[n][1] where n is your item number.

Javascript array without quotes

I've been pulling my hair out trying to figure this out.
I'm using ZingChart to plot some data from a MySQL query. I put the data into a PHP array, and then use:
var myData = <?php echo json_encode($combined); ?>;
to put it into a javascript array.
If I do:
document.write(myData[0]);
then it shows the correct value for that index. When I try to use the array with the ZingChart's JSON, I see that it puts quotes around all the data, which for some reason it doesn't like. If I manually remove the quotes using notepad, the data displays great, so I know it's just a matter of getting rid of these quotes somehow.
Here's how it looks, for example, when I view the source from the page:
var myData = [["1466766034467","71.191"],["1466766094482,71.1986"]];
I've tried many ways and spent many hours trying to get the data passed into JSON without the quotes, but I know just enough to be dangerous, so hopefully someone can guide me.
document.write(myData[1]);
will result: 1466766094482,71.1986
Thanks in advance.
Assuming you are running a reasonably current version of php you can add JSON_NUMERIC_CHECK to json_encode() options argument
json_encode($combined, JSON_NUMERIC_CHECK);
See json_encode docs
Or in javascript iterate arrays and cast values to number using any variety of methods
myData.forEach(function(arr){
arr[0] = +arr[0];
arr[1] = +arr[1];
})
You can parse the String types into Int and Float. For your 2-item arrays, the following works with the map function:
myData.map(function(x){ return [parseInt(x[0]),parseFloat(x[1]) });
// or in ES6 notation
myData.map( x => [parseInt(x[0]),parseFloat(x[1])] );
General Solution
Inspired by #charlietfl's solution, here's a generic function parseNumeric for converting all numeric data within an array. It will recurse through any nested arrays it finds.
var myData = [["1466766034467","71.191"],["1466766094482","71.1986"]];
// Convert data to numeric, including recursion within nested arrays
// Usage parseNumeric( myData );
function parseNumeric(x,y,z) {
if( Object.prototype.toString.call( x ) === '[object Array]' ) {
x.forEach(function(c,i,a){numConvert(c,i,a)});
} else if ( typeof z != 'undefined' ) {
z[y] = +x
}
}
parseNumeric( myData );
// => [[1466766034467,71.191],[1466766094482,71.1986]];

return of CERT_FindUserCertByUsage in javascript

I am trying to understand the relationship between C++ dll and JavaScript.
There is a js code:
cert = CERT_FindUserCertByUsage(certDB, certName.nickname,certUsageEmailSigner, true, null);
where cert is defined as
let cert = null;
However in C++, cert is a struct
CERTCertificateStr {
char *subjectName;
char *issuerName;
SECItem derCert; /* original DER for the cert */
.... }
I am trying to get the subject name in javascript and I continue the code with
let a = cert.contents.subjectName;
It is unsuccessful. It logs error as "cannot get content of undefined size"
Anything that i have missed in between C++ and javascript?
How can i print the subjectName in javascript?
I think you are doing jsctypes and you are on the right track. To get the js string though you have to tag on a readString() after casting it to an array with a certain length, its ok to go past the actual length as readString() will read up till the first null char which is \x00. Although if you know the exact length that's always best (you dont have to do the length + 1 for null term) because then you save memory as you dont have to unnecessarily allocate a buffer (array in jsctypes case) more then the length needed.
So try this:
let a = ctypes.cast(cert.contents.subjectName, ctypes.char.array(100).ptr).contents.readString();
console.log('a:', a);
The error cannot get contents of undefined size happens in situations like this:
var a = ctypes.voidptr_t(ctypes.char.array()('rawr'))
console.log('a:', a.contents);
this spits out
Error: cannot get contents of undefined size
So in order to fix that what we do is this:
var b = ctypes.cast(a, ctypes.char.array(5).ptr)
console.log('b:', b.contents);
and this succesfully accesses contents, it gives us (by the way, i used 5 for length which is 4 for the length of rawr + 1 for null terminator but i really didnt have to do that i could have used length of just 4)
CData { length: 5 }
so now we can read the contents as a js string like this:
console.log('b:', b.contents.readString());
and this spits out:
rawr
ALSO, you said the functions returns a struct, does it return a pointer to the struct? Or actually the struct? I would think it returns a pointer to the struct no? so in that case you would do this:
let certPtr = CERT_FindUserCertByUsage(certDB, certName.nickname,certUsageEmailSigner, true, null);
let certStruct = ctypes.StructType('CERTCertificateStr', [
{'subjectName': ctypes.char.ptr},
{issuerName: ctypes.char.ptr},
{derCert: ctypes.voidptr_t}
]);
let cert = ctypes.cast(certPtr, certStruct.ptr).contents;
let a = cert.contents.subjectName.readString();

Can't get JSON properties to display via jQuery

For some reason I just can't seem to be able to display properties from this JSON string:
http://www.easports.com/iframe/fifa14proclubs/api/platforms/PS4/clubs/51694/members
I've sat here for the last 2-3 hours trying out different ways to select single properties such as the name of the first person in the array. A couple selectors I've tried:
$("#output").append(data.raw[0].176932931.name);
$("#output").append(data.raw[0][0].name);
I always get the same error. "data.raw[0] is undefined". The JSON string is valid, I'm able to output the whole string to my page using:
document.getElementById('output').innerHTML=data.toSource();
Parsing it into a JSON object gives me another error because it already is a JSON object. By using console.log(data) I'm able to view the JSON object properly in Firebug.
data is the name of the Javascript JSON object variable that is being returned from my YQL statement.
Please, if anyone could provide some examples as to how I should go about accessing the properties of the above JSON string, that would be great.
UPDATE:
Here's the callback function from my YQL statement:
function cbfunc(json)
{
if (json.query.count)
{
var data = json.query.results.json;
$("#output").append(data.raw[0]["176932931"].name);
}
You need to use bracket notation, as identifiers starting with digits are invalid
$("#output").append(data.raw[0]["176932931"].name);
as "176932931" is an integer key so you have to access like json["176932931"].
For example
data.raw[0]["176932931"].name
see fiddle here
.count isn't a property of a json object. Try this:
var something = {"raw":[{"176932931":{"name":"Shipdawg","blazeId":176932931,"clubStatus":0,"onlineStatus":0,"nucleusId":2266699357,"personaName":"Shipdawg"},"182141183":{"name":"Beks8","blazeId":182141183,"clubStatus":0,"onlineStatus":0,"nucleusId":2272736228,"personaName":"Beks8"},"219929617":{"name":"ChelseaFC_26","blazeId":219929617,"clubStatus":0,"onlineStatus":0,"nucleusId":2304510098,"personaName":"ChelseaFC_26"},"457588267":{"name":"Lazy__Rich","blazeId":457588267,"clubStatus":0,"onlineStatus":0,"nucleusId":2495578386,"personaName":"Lazy__Rich"},"517570695":{"name":"x0__andrew__0x","blazeId":517570695,"clubStatus":0,"onlineStatus":1,"nucleusId":2549150176,"personaName":"x0__andrew__0x"},"912396727":{"name":"mizz00-","blazeId":912396727,"clubStatus":0,"onlineStatus":1,"nucleusId":1000118566560,"personaName":"mizz00-"},"915144354":{"name":"MisterKanii","blazeId":915144354,"clubStatus":2,"onlineStatus":0,"nucleusId":2281969661,"personaName":"MisterKanii"}}]}
function cbfunc(json)
{
if (json.raw.length)
{
$("#output").append(json.raw["0"]["176932931"].name);
}
}
cbfunc(something);
Tell me if this works for you:
function cbfunc(json)
{
$each(json, function(key, object){
console.log(key, object);
});
var raw = query.results.json.raw;
console.log(raw );
// uncomment it if you want some extra check.
if (/*typeof data.raw !=='undefined' && */data.raw.length > 0)
{
//console.log(data.raw[0]["176932931"].name);
//$("#output").append(data.raw[0]["176932931"].name);
}
}
If this works for you there's no need to reference the object to data, simply use the object its self.
JS fiddle: http://jsfiddle.net/q8xL3/2/

Categories