How to fully dump / print variable to console in the Dart language? - javascript

Hey there I am searching for a function which is printing a dynamic variable as completely as possible to the console in Dart language.
In PHP for instance I would use var_dump() in order to get all information about a variable.
In JavaScript I would do one of the following:
1) Convert Object to JSON and print console.log(JSON.stringify(obj))
2) Or a custom function like this:
function dump(arr,level) {
var dumped_text = "";
if(!level) level = 0;
//The padding given at the beginning of the line.
var level_padding = "";
for(var j=0;j<level+1;j++) level_padding += " ";
if(typeof(arr) == 'object') { //Array/Hashes/Objects
for(var item in arr) {
var value = arr[item];
if(typeof(value) == 'object') { //If it is an array,
dumped_text += level_padding + "'" + item + "' ...\n";
dumped_text += dump(value,level+1);
} else {
dumped_text += level_padding + "'" + item + "' => \"" + value + "\"\n";
}
}
} else { //Stings/Chars/Numbers etc.
dumped_text = "===>"+arr+"<===("+typeof(arr)+")";
}
return dumped_text;
}
However in Dart if I do print(variable) I get something like Instance of 'FooBarObject'. I cannot just convert an object to JSON like in JavaScript as this is not possible for all objects.
So my question in detail:
Is where a function or custom function in dart which can print a variable with unknown type (object, array, etc.) including all (public) properties as well as nested objects and variables to my console? Or which function is closest to this desire?

dart:developer library includes inspect function that allows debuggers to open an inspector on the object.
To use it add:
import 'dart:developer';
And then you can see your inspected variable/object in console with:
inspect(myVar);

There is no built in function that generates such an output.
print(variable) prints variable.toString() and Instance of 'FooBarObject' is the default implementation. You can override it in custom classes and print something different.
You can use reflection (https://www.dartlang.org/articles/libraries/reflection-with-mirrors) to build a function yourself that investigates all kinds of properties of an instance and prints it the way you want.
There is almost no limitation of what you can do and for debugging purposes it's definitely a fine option.
For production web application it should be avoided because it limits tree-shaking seriously and will cause the build output size to increase notable.
Flutter (mobile) doesn't support reflection at all.
You can also use one of the JSON serialization packages, that make it easy to add serialization to custom classes and then print the serialized value.
For example
https://pub.dartlang.org/packages/dson
I think there are others, but I don't know about (dis)advantages, because I usually roll my own using https://pub.dartlang.org/packages/source_gen

If it's a map then you can convert to JSON. First import convert package from flutter.
import 'dart:convert';
then convert to JSON and print
print(json.encode(yourMapVariable));
Update
Above answer is for map. For class / object add to toString() method.
Eg: say we have a user class
class User {
String name;
String address;
toString() {
return "name: " + name + ", address: " + address;
}
}
You can auto generate this toString() method using your IDE.

Simple little trick does the job
void printObject(Object object) {
// Encode your object and then decode your object to Map variable
Map jsonMapped = json.decode(json.encode(object));
// Using JsonEncoder for spacing
JsonEncoder encoder = new JsonEncoder.withIndent(' ');
// encode it to string
String prettyPrint = encoder.convert(jsonMapped);
// print or debugPrint your object
debugPrint(prettyPrint);
}
// To use simply pass your object to it
printObject(yourObject);

Instance of 'FooBarObject' This happens when you try to directly do print(object);
Even if you use convert package from flutter, it would throw Uncaught Error: Converting object to an encodable object failed:
To resolve this issue, first, make sure your model class or data class contains fromJson and toJson methods.
If you do so, your model class would look like this.
class User {
String name;
String gender;
int age;
User({this.name, this.gender, this.age});
User.fromJson(Map<String, dynamic> json) {
name = json['name'];
gender = json['gender'];
age = json['age'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name'] = this.name;
data['gender'] = this.gender;
data['age'] = this.age;
return data;
}
}
And to print this as json import convert package
import 'dart:convert';
And call json.encode
//after initializing the user object
print('value is--> ' + json.encode(user);
Which will print the data as
value is--> {"name": "Vignesh","gender": "Male","age": 25}

use await keyword with an object in async function
void _registerUser() async { print(await form.result); }

If you want to know more about an instance of any class in an android studio click on a class name before variable then press ctrl+b it will take you to the class file where this object belongs from there you can see user attributes and methods of this class.

Try this one..
void printWrapped(String text) {
final pattern = new RegExp('.{1,800}'); // 800 is the size of each chunk
pattern.allMatches(text).forEach((match) => print(match.group(0)));
}

Related

GraalVM how to return an array from a method to the guest language?

I'm playing around with GraalVM (Truffle) in OpenJDK 17, and would like to know what the correct way is to return values to the guest language from method calls? Right now I'm struggling with passing a String[] array back.
Exmaple:
Java (host)
class Services
{
Value message;
#HostAccess.Export
public String[] getArrayString()
{
return new String[]{"s1", "s2", "s3"};
}
#HostAccess.Export
public void setMessage( Value v )
{
message = v;
message.pin();
}
}
...
String jsScript = " ... " // see below
try ( Context context = Context.newBuilder().allowHostAccess(HostAccess.SCOPED).build() )
{
Services s = new Services();
context.getBindings("js").putMember("services", s);
context.eval("js", jsScript);
}
JavaScript (guest)
var a = services.getArrayString();
b = '';
for ( var c in a ) b += c;
services.setMessage('' + a + ' // ' + b)
The final message value is "[object Object] // " (b is blank), however I expected something like "[object Object] // s1s2s3".
I've also tried the return types Object[] and ArrayList<String>. I'm not sure why I can't access the elements of the array, either I'm not passing the array back correctly, or I'm not accessing it correctly within the JavaScript script. The examples I've found in the GraalVM docs are always about passing values directly from the host to the guest, but I'd like to do it via a method call - how is that done?
I've finally found a way to pass an array from the host to the guest - using ProxyArray.
https://www.graalvm.org/22.1/reference-manual/embed-languages/#computed-arrays-using-polyglot-proxies
Reading through the Graalvm documentation and experimenting with the very primative examples they provide, I came up with the following changes to my Services class:
ArrayList<String> array = new ArrayList<String>();
#HostAccess.Export
public void prepareList()
{
array.add("s1");
array.add("s2");
array.add("s3");
}
#HostAccess.Export
public ProxyArray getArray()
{
return new ProxyArray() {
#Override
public Object get( long index )
{
return array.get((int)index);
}
#Override
public void set( long index, Value value )
{
// TODO Auto-generated method stub
}
#Override
public long getSize()
{
return array.size();
}
};
}
And finally the guest call looks like this:
services.prepareList();
var a = services.getArray();
b = '';
for ( i = 0; i < a.length; i++ ) b += a[i];
services.setMessage('' + a + ' // ' + b)
And the value of the message is then as expected "[object Object] // s1s2s3"
Hope someone finds this useful ... and if you have a better way of returning objects (Array, Hashtable, whatever) post your answers here - thanks.
First I would give a straight forward answer to your question. To pass an array from Java scope to the guest language scope, you can just send the Java array/list as input to the execute method. For example:
Context context = Context.newBuilder().allowAllAccess(true).build();
int intArray[] = {1,2,3};
Value ret = context.eval("js", "(function getArray(a) {console.log(a[2]);})").execute(intArray);
The above should print 3 in the JS scope.
Now I decide to add the following paragraphs because after reading your code as well as those in some proposed answers, I think it could be of help.
Say you have a Java code snippet like the one below which returns an array from the JS context.
Value val = context.eval("js", "(function getArray() {return [1,2,3];})").execute();
It is not possible to directly access the whole array object from val in the Java language scope because the memory layout of Java arrays is different from the memory layout of JS arrays. However you can obtain elements at different indices of the JS array from within the Java scope as follows:
int index2 = val.getArrayElement(2).asInt();
System.out.println(index2);
The above should print the value 3.
In order to obtain the full array in the Java scope, you must do an explicit array copy. The classic way to do this is to leverage the technique described here: https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Value.html#as-org.graalvm.polyglot.TypeLiteral-
Using that technique one can define an INTEGER_LIST TypeLiteral as such:
public static final TypeLiteral<List<Integer>> INTEGER_LIST =
new TypeLiteral<List<Integer>>() {};
And then return the polyglot Value as an INTEGER_LIST as follows:
List<Integer> intList = context.eval("js", "(function getArray() {return [1,2,3];})").execute().as(INTEGER_LIST);
System.out.println("JS array in Java scope: " + intList);
The above print should produce: [1,2,3]. This strategy also does an explicit array copy in the back ground but it is neat, more or less.
You could apply exactly the same strategy for your String array, by defining a TypeLiteral like:
public static final TypeLiteral<List<String>> STRING_LIST =
new TypeLiteral<List<STRING>>() {};
And obtaining the String list/array in Java scope via ...execute().as(STRING_LIST);. This should give you your String array in the Java scope.

Apex equivalent to Javascript For In

I have a variable that contains a list of account objects and I want to iterate through all of the fields of those accounts.
I am able to accomplish this through javascript using the below code, but I don't want to take things out of apex if I don't have to.
Does apex have an equivalent to Javascript's "IN" that would allow me to compare all fields to the same field in the next record like below?
for (var key in dataGet.accounts[i]) {
if (dataGet.accounts[i][key] != dataGet.accounts[i+1][key]) {
dataGet.accounts[i][key] = dataGet.accounts[i+1][key];
}
}
Thanks!
To get all fields populated in one record as a key => value kind of access you can use accounts[i].getPopulatedFieldsAsMap()
To compare all fields on 2 objects (whether they're populated or not) you should read up on "Dynamic Apex" and "describe" operations. Something like this will get you all API names on the object:
Map<String, Schema.SObjectField> fieldsMap = Schema.SObjectType.Account.fields.getMap();
And then you can iterate on the map keys
for(String field : fieldsMap.keyset()){
System.debug(field + ': ' + accounts[i].get(field));
}
If you don't work with sObjects but with some classes which you can't control (meaning you can't just change internal implementation to use Map<String, String> to store key-value pairs or something)... This could work. Apex doesn't have reflection.
public with sharing class Stack47339633{
public String name, some, other, property;
public Integer someInt;
public Date d;
}
Stack47339633 obj1 = new Stack47339633();
obj1.name = 'hello';
obj1.some = 'world';
obj1.someInt = 13;
obj1.d = System.today();
Stack47339633 obj2 = new Stack47339633();
obj2.name = 'hello';
obj2.some = 'stackoverflow';
obj2.someInt = -7;
obj2.d = System.today();
// Let's treat them as JSON objects...
Map<String, Object> o1 = (Map<String,Object>) JSON.deserializeUntyped(JSON.serialize(obj1));
Map<String, Object> o2 = (Map<String,Object>) JSON.deserializeUntyped(JSON.serialize(obj2));
Map<String, Object> o3 = new Map<String, Object>();
// ...compare, write identical fields to result object
for(String s : o1.keyset()){
System.debug(s + ':' + o1.get(s) + ' == ' + o2.get(s) + '?');
if(o1.get(s) == o2.get(s)){
System.debug('match!');
o3.put(s, o1.get(s));
}
}
// and cast that result object back to real class instance
Stack47339633 obj3 = (Stack47339633) JSON.deserialize(JSON.serialize(o3), Stack47339633.class);
System.debug('Full result: ' + obj3);
System.debug('Name : ' + obj3.name);
System.debug('someint : ' + obj3.someInt);
System.debug('d : ' + obj3.d);
It's not pretty with all this casting to JSON and back but it gets the job done.
There will be situations where serialization can fail (for example holding references to this), if something is marked as transient it might not survive... But I don't think you'll have better option.
Check also these:
https://salesforce.stackexchange.com/questions/135891/can-we-access-class-properties-dynamically-with-object-class
https://salesforce.stackexchange.com/questions/16780/how-to-get-the-attribute-class-list

How to append function with object as a parameter in javascript string?

<script>
//some code here
var content = '<div onclick="populatedata(\'' + obj.Records[t] + '\')" >';
function populatedata(obj) {
console.log(typeof obj);
}
</script>
Now output of the above code is string, but I want object content in function populatedata.
As #nnnnnn Suggested I had passed index of record in function and received it in populatedata.
<script>
//some code here
var content = "<div onclick="populatedata("+t+")>";
function populatedata(index) {
console.log(obj.Records[index]); //this is just for illustration
//further processing here
}
</script>
You didn't clarify what type obj.Records[t] is, but I guess it is an object. So you have problem because result of concatenation with a String is always a new string, with toString() applied to non-string types (obj.Records[t] in your case).
What you need to do is to stringify your object manually so that you control string presentation yourself:
var content = '<div onclick="populatedata(' + JSON.stringify(obj.Records[t]) + ')">';
Then result of such concatenation would be something like (if obj.Records[t] = {name: 123}):
<div onclick="populatedata({"name":123})">
which will allow populatedata invocation with proper parameter.
If you want to be able to further process the argument of populatedata, you'll first want to stringify it, then change your function from logging the typeof to just the object.
var content = "<div onclick='populatedata(" + JSON.stringify(obj.Records[t]) + ")'>test</div>";
function populatedata(obj) {
// do things with obj here
console.log(obj);
}
However, as Oriol mentioned in a comment on your question, you probably don't want to take that approach. It's better to:
Manage handlers through the dom API
Pass data objects in programmatically as opposed to embedding them into the dom

Java: Get JavaScript Array Elements from page

I am at a point where I can pull a single javascript declaration such as:
var cars = ["Saab", "Volvo", "BMW"];
parsed from a page.
I would like to be able to get all the elements of the array ("Saab", "Volvo", "BMW") from this declaration.
Should I be using some javascript engine for this, or what else would be the best way to get javascript variable values from my Java code.
I would hate to reinvent the wheel if something is already out there that is able to do this, so I am just looking for advice on something I can use to do this function.
I assume you found a way to transport that javascript object/array into your Java domain as a String or Stream. What you want now is a JSON parser.
One way is to use json.org or other libraries. Further information about json parsing can be found in this thread:
How to parse JSON in Java
The [org.json][1] library is easy to use. Example code below:
import org.json.*;
JSONObject obj = new JSONObject(" .... ");
String pageName = obj.getJSONObject("pageInfo").getString("pageName");
JSONArray arr = obj.getJSONArray("posts");
for (int i = 0; i < arr.length(); i++)
{
String post_id = arr.getJSONObject(i).getString("post_id");
......
} You may find extra examples from: [Parse JSON in Java][2]
Downloadable jar: http://mvnrepository.com/artifact/org.json/json
[1]: http://www.json.org/java/index.html
[2]: http://theoryapp.com/parse-json-in-java/
You might also want to look into jsonb (https://jcp.org/en/jsr/detail?id=353) that was introduced with Java 7. You can bind an object model and transform JSON objects into java objects and vice versa.
you can iterate through all the values in 'window'
for ( var key in window )
{
if ( typeof window]key] == 'object' && window]key].length > 0 )
{
//this is the array you are looking for
}
}
You can get access to javascript object from java by using httpunit
Method 1: JSON parser, as Alex's answer.
Method 2: Javascript parser for Java
Method 3: Regular Expression (A weird way I figured out!)
First pattern is var\s+([a-zA-Z0-9]+)\s+=\s+\[(.*)\]\s*;*
var + one or more space(s) + variable name($1) + one or more space(s) + equals sign + one or more space(s) + array content($2) + ......
Second pattern is "(.*?)", get the string between two quotation marks.
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class JSParser {
public String arrayName;
private String tempValues;
public ArrayList<String> values = new ArrayList<String>();
public boolean parseJSArray(String arrayStr){
String p1 = "var\\s+([a-zA-Z0-9]+)\\s+=\\s+\\[(.*)\\]\\s*;*";
Pattern pattern1 = Pattern.compile(p1);
Matcher matcher = pattern1.matcher(arrayStr);
if(matcher.find()){
arrayName = matcher.group(1);
tempValues = matcher.group(2);
Pattern getVal = Pattern.compile("\"(.*?)\"");
Matcher valMatcher = getVal.matcher(tempValues);
while (valMatcher.find()) { // find next match
String value = valMatcher.group(1);
values.add(value);
}
return true;
}else{
return false;
}
}
}
With JDK 8 the code bellow works :
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
String js = "var carsfromjs = [\"Saab\", \"Volvo\", \"BMW\"]";
engine.eval(js);
String[] cars = (String[])engine.eval("Java.to(carsfromjs, \"java.lang.String[]\")");
for(int i=0; i<cars.length; i++){
System.out.println(cars[i]);
}
You can find many ways to access Javascript code throught "nashorn" :
http://winterbe.com/posts/2014/04/05/java8-nashorn-tutorial/
http://www.oracle.com/technetwork/articles/java/jf14-nashorn-2126515.html
http://docs.oracle.com/javase/8/docs/technotes/guides/scripting/nashorn/

Custom object to JSON then back to a custom object?

I've seen very similar questions to this, but I can't quite decide if they was answered clearly - maybe I'm being a bit dense, sorry.
I want to have the convenience (and clarity) of my own object, call it a CardboardBox(). It won't contain code, just data. I want to write this to a database and read it back later, but obviously, it is a type Object() when it's read back. All I can think of to find out what it used to be is:
Have a member variable type that I set to CARDBOARD_BOX
Instantiate a new CarbardBox() and use a function (in the box) to copy the properties of Object() to the new CardboardBox() object
Is there a better way of doing this? I'm pretty sure I can change the actual type.
function CardboardBox() {
this.type = "CARDBOARD_BOX"
this.name = "No set";
this.populate = new function(obj) {
// populate this object with obj properties
}
var box = new CarboardBox(); // CarboardBox
box.name = "My Box";
send = JSON.stringyfy(box);
.
.
.
obj = JSON.parse(send); // Object
if (obj.type == "CARDBOARD_BOX") {
savedBox = new CardboardBox();
savedBox.populate(obj);
}
Thanks in advance...
Steve
[edit] My test code.
function CardboardBox(n) {
this.name = n;
}
var box = new CardboardBox("My Box");
send = JSON.stringify(box); // JSON CarboardBox()
obj = JSON.parse(send, function fn(obj) { // Object() returned
log("OB: "+obj.type);
return obj.type === 'CardboardBox' ? new CardboardBox(obj) : CardboardBox;
});
console.log(obj);
Output is:
OB: undefined utils.js:40
OB: undefined utils.js:40
function CardboardBox(n) {
this.name = n;
}
One possible solution is the following:
function CardboardBox(n) {
if(typeof(n) == 'string') {
//build from name string
this.name = n;
} else {
//build from object
this.name = n.name;
}
//add in this object's "type" in a place
//that is unlikely to exist in other JSON strings
this.__type = 'CardboardBox';
}
var box = new CardboardBox("My Box");
send = JSON.stringify(box), // JSON CarboardBox()
obj = JSON.parse(send, function(key, val) {
//if this is an object, and is CardboardBox
if(typeof(val) === 'object' && val.__type === 'CardboardBox')
return new CardboardBox(val);
return val;
//or if your object is in a context (like window), and there are many of
//them that could be in there, you can do:
//
//if(typeof(val) === 'object' && context[val.__type])
// return new context[val.__type](val);
});
console.log(obj);
Basically store the object type in a place you know to look for later on when parsing the json. if you have multiple objects you can instantiate in a single scope the second parse method may be more appropriate. This also will account for objects in the JSON that are not CarboardBoxs.
Edit Here is a jsFiddle of this method in action.
Overall, you're correct: Javascript doesn't have any built-in way to serialize anything beyond plain objects, so going to and from JSON will not produce a particular class when you deserialize it. So you need to either work out serialization/deserialization yourself, or use a library that provides some support.
I personally like Backbone.js for this problem, as it handles serializing and deserializing quite well. You define a model class, which include a method to save its data to a server in a serialized form, and a method to deserialize it back to the model. The key design issue here is that deserializing is performed knowing the model you're deserializing to:
you either call myModel.fetch() to get data from the server based on the model id, or
you pass a bunch of new data to the model constructor: new Model(serializedData), or
you pass an array of data for multiple models to a collection that knows the model type: new ModelCollection(arrayOfSerializedData).
What Backbone doesn't do is deal with type-casting data of an unknown type. When I've dealt with this, I've usually done something similar to #Chad's response, but using an intermediary; you could see this as a proxy model, or as a factory:
var classes = {
CardboardBox: ...,
AluminumBox: ...
}
function Deserializer(json) {
// parse if you're actually dealing with a string
var data = JSON.parse(json),
// now look for some custom type flag - you'll need to set this yourself
type = data.type,
// class lookup, perhaps with a default
Cls = classes[type] || DefaultType;
return new Cls(data);
}
var obj = new Deserializer(send);
obj instanceof CardboardBox; // should work
This still relies on a custom flag to switch types, though - I'm not sure there's any way around this.

Categories