I have this code snippet from javascript (which i am not familiar with) , but i need this thing to pass in one of my java method ,
example.setChoices([{ value : 'One', label : 'Label One', disabled : true }], 'value', 'label', false);
I am looking into w3schools and other javascript sources , but it doesnt looks to be a simple map ..
I am not getting , what kind of Map would this be in java
My goal is to send this data to my java method .
Completely wrong approach, but possible - you can create <Object,Object> map.. Every class is a child of object,
except that you probably can't do it other way, because in JS you can see mixed datatypes.
You can of course eg. convert boolean to string, guessing its still better approach to have "raw Object map"..
Map<Object, Object> test = new HashMap<>();
test.put("firstString", "first");
test.put("secondString", "second");
test.put("thirdBool", true);
/* print
Iterator entries = test.entrySet().iterator();
while (entries.hasNext()) {
Map.Entry entry = (Map.Entry) entries.next();
System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
}
*/
Reg. provided code something like :
Map<Object, Object> test = new HashMap<>();
test.put("value", "value");
test.put("label", "label");
test.put("disabled", false);
Reg. custom class, the better way how to deal is to create eg.
class someFooObject{
private String value;
private String label;
private boolean disabled;
someFooObject(String value,String label,boolean disabled){
this.value=value;
this.label=label;
this.disabled=disabled;
}
public String getValue(){
return this.value;
}
public String getLabel(){
return this.value;
}
public boolean isDisabled(){
return this.value;
}
}
Then you can use it as usual for put to map
Map<Integer, someFooObject> test = new HashMap<>();
test.put(0,new someFooObject("first","1 label",false));
//Check for params
test.get(0).isEnabled();
test.get(0).getValue();
test.get(0).getLabel();
Default values are not supported in Java, but you can override constructor as:
someFooObject(String value,String label,boolean disabled){
this.value=value;
this.label=label;
this.disabled=disabled;
}
someFooObject(String value,String label){
this.value=value;
this.label=label;
//kind of default value
this.disabled=true;
}
Related
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.
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
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)));
}
whats the equivalent for creating json serialized data for this javascript code:
chartData.push({date: "bla",value1: "bla1",value2: "bla2"});
chartData.push({date: "blx",value2: "blax2"});
The json will look something like this:
[{
"date": bla,
"value1": bla1,
"value2": bla3,
}, {
"date": blx,
"value2": blax2
}]
I tried creating a list of class, but when i dont assign the value1 property, the value will just be zero. But i dont want the property to be displayed in the json at all, when not assigned.
List <Models.HistoClass> HistoData= new List<Models.HistoClass>();
HistoData.Add(new Models.HistoClass {date="bla",value1="bla1",value2="bla3"});
HistoData.Add(new Models.HistoClass { date= "blx", value2="blax2" });
How should i create the datamodel to have a json like that?
Thanks!
If you're creating data manually in the way you show, you could use anonymous types to construct data the looks exactly how you want:
List <object> HistoData= new List<object>();
HistoData.Add(new {date="bla",value1="bla1",value2="bla3"});
HistoData.Add(new { date= "blx", value2="blax2" });
However, if you want to use a strong type and/or your code is initializing the values in the same way every time, but sometimes values just aren't present, then you can make the values nullable and tell JSON.NET to ignore null properties when serializing:
public class HistoClass
{
public string date;
[JsonProperty(NullValueHandling=NullValueHandling.Ignore)]
public int? value1;
[JsonProperty(NullValueHandling=NullValueHandling.Ignore)]
public int? value2;
}
...
List <Models.HistoClass> HistoData= new List<Models.HistoClass>();
HistoData.Add(new Models.HistoClass {date="bla",value1="bla1",value2="bla3"});
HistoData.Add(new Models.HistoClass { date= "blx", value2="blax2" });
You can use Json.NET's ShouldSerialize:
Public class DateAndValues
{
public DateTime Date {get; set;}
public Int32 Index {get; set;}
public Int32 Value1 {get; set;}
public Int16 Value2 {get; set;}
public bool ShouldSerializeValue1 ()
{
// your condition for serialization, for example even objects:
this.Index % 2 != 0;
}
}
This description:
To conditionally serialize a property, add a method that returns boolean with the same name as the property and then prefix the method name with ShouldSerialize. The result of the method determines whether the property is serialized. If the method returns true then the property will be serialized, if it returns false then the property will be skipped.
is taken from this link.
To actually serialize, of course, use:
var firstObj = new DateAndValues { Index = 1, .. };
var secondObj = new DateAndValues { Index = 2, .. };
string json =
JsonConvert.SerializeObject(new[] {firstObj, secondObj}, Formatting.Indented);
and according to the condition above, secondObj (even Index) will not have Value1.
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/