Java array of Entities to JavaScript array - javascript

I want to put global property named "entities" in JS scope. Entity is basically Java class describing Person.
public class EntityJS extends ScriptableObject {
private String firstName;
private String lastName;
private Double salary;
private String email;
#Override
public String getClassName() {
return "Entity";
}
public EntityJS() {
}
public EntityJS(String firstName, String lastName, Double salary, String email) {
this.firstName = firstName;
this.lastName = lastName;
this.salary = salary;
this.email = email;
}
public void jsConstructor() {
this.firstName = "";
this.lastName = "";
this.salary = 0.;
this.email = "";
}
public void jsSet_salary(Double value) {
this.salary = value;
}
public Double jsGet_salary() {
return this.salary;
}
public void jsSet_firstName(String value) {
this.firstName = value;
}
//the rest of getters & setters
}
Entity class is almost the same class like EntityJS, except it extends only java Object.
I want to allow javascript user modify global variable "entities". After executing user's script, I want to retrieve this object back to Java (and perform some operations later on).
I've commented interesting lines with results and expected returned values.
Here is my code of trying to execute user's code:
public String execute(String code, ObservableList<Entity> entities) {
Context context = Context.enter();
try {
Scriptable scope = context.initStandardObjects();
ScriptableObject.defineClass(scope, EntityJS.class, true, true);
EntityJS[] objects = new EntityJS[entities.size()];
for(int i = 0; i < entities.size(); ++i){
objects[i] = new EntityJS(entities.get(i).getFirstName(), entities.get(i).getLastName(), entities.get(i).getSalary(), entities.get(i).getEmail());
}
ScriptableObject.putProperty(scope, "e1", Context.javaToJS(objects, scope));
// typing "e1" (which is equal to "code" value) returns "[Lentity.EntityJS;#7959b389"
Object[] array = entities.toArray();
ScriptableObject.putProperty(scope, "e2", array);
// same for e1
Object wrappedOut = Context.javaToJS(entities, scope);
ScriptableObject.putProperty(scope, "e3", wrappedOut);
//this works quite nice, but it doesn't behave like JS object
//it returns, good-looking array:
//[Entity{firstName='Alwafaa', lastName='Abacki', salary=1000.0, email='zdzisiek#adad.com'},
//Entity{firstName='chero', lastName='Cabacki', salary=2000.0, email='bfadaw#dadaad.com'}]
//Unfortunately, if I want to get e.g. salary value I have to call
//e.get(0).getSalary() which returns string :(
//if I want to add number I have to call
//Number(e.get(0).getSalary()) to get Number
ScriptableObject.putProperty(scope, "e4", Context.javaToJS(objects[0], scope));
//this results in "TypeError: Cannot find default value for object."
Object result = context.evaluateString(scope, code, "<cmd>", 1, null);
return context.toString(result);
} catch (Exception ex) {
System.out.println(ex.getMessage());
return ex.getMessage();
} finally {
Context.exit();
}
}
I want to give user "entities" JS-like array, which could be modified e.g. this way:
entities.forEach(function(entity){entity.salary += 1000;})
I'd like salary property to be Number, of course.
Does someone know how can I approach this?
Thanks in advance

You can transfer Java Objects into JSON String on the server side and pass it to the client - javascript. When the client receives response from the server (JSON String containing your ojects), you can parse json.
You can convert Java Objects into JSON (on the server side), check this tutorials:
GSON https://www.mkyong.com/java/how-do-convert-java-object-to-from-json-format-gson-api/
Jackson https://www.mkyong.com/java/jackson-2-convert-java-object-to-from-json/
This is how to parse JSON object in js.
https://www.w3schools.com/js/js_json_parse.asp
I want to allow javascript user modify global variable "entities". After executing user's script, I want to retrieve this object back to Java (and perform some operations later on).
You can make an AJAX request to the server passing modified objects. Again, on the js side you convert these objects into JSON, then pass them to the server, and parse JSON String into a collection (array) of your objects.
This is how to convert javascript objects into JSON String
Convert JS object to JSON string
I have Java Application, which uses Rhino (as in tags). I have TextArea, where user types JS code. I need to give user the entities object.
So, pass the text entered by the user into your server, parse it. Make sure that you are passing valid JSON though.

Depends on your JS version, you can do the following:
ES5
function Person(firstName, lastName, salary, email) {
this.firstName = firstName;
this.lastName = lastName;
this.salary = salary;
this.email = email;
}
var john = new Person("john", "smith", 500, "john.smith#john.com");
var jane = new Person("jane", "doe", 650, "jane.doe#jane.net");
var people = [john, jane];
//mutating the original values
people.forEach(function(person) {person.salary += 500})
ES6
class Person {
constructor(firstName, lastName, salary, email) {
this.firstName = firstName;
this.lastName = lastName;
this.salary = salary;
this.email = email;
}
}
let john = new Person("john", "smith", 500, "john.smith#john.com");
let jane = new Person("jane", "doe", 650, "jane.doe#jane.net");
let people = [john, jane];
people.forEach(person => person.salary += 500);

Related

2-way synchronization of text structure?

I know the title is a bit confusing, but I have no idea to describe precisely what I mean.
I have a minimal demo below:
class A{
name: string;
age: number;
toString(){
return `
My name is: ${this.name},
My age is: ${this.age}
`
}
fromTextToData(text: string){
//Do something, regex or something?
this.name = ...;
this.age = ...;
}
}
main(){
let a = new A();
a.name = "Name 1";
a.age = 20;
let text = a.toString();
var revert = a.fromTextToData(text);
}
The best way I can think about it is using Regex expression, but if the data is large or something the structure is duplicated to its others, I think it's not really a good solution.
The second solution I can think of is using a data structure such as JSON or XML.
But I still want some suggestions from you.
That is possible, but I would first change a few things in your code:
Allow the constructor to take arguments for initialising its properties:
constructor(name, age) {
this.name = name;
this.age = age;
}
Make the reversing method a static method that returns a new instance of A instead of overwriting the properties of an existing instance. I would also just call it fromText
To better ensure that both toString and fromText rely on the same string format, define a kind of template as a static property of the A class. This template could take different forms. Here I will propose an array:
static template = ["\nMy name is: ", "\nMy age is: ", "\n"]
So the idea is that the dynamic parts get inserted between those strings. On the other hand, the reverse action can identify these strings and extract what is in between them with (.*?) as part of the regular expression.
class A {
static template = ["\nMy name is: ", "\nMy age is: ", "\n"]
constructor(name, age) {
this.name = name;
this.age = age;
}
toString(){
return [this.name, this.age]
.map((data, i) => A.template[i] + data)
.concat(A.template.slice(2))
.join("");
}
static fromText(text) {
const regex = RegExp(A.template.join("(.*?)"));
// Get the match, and extract with slice the captured groups
return new A(...text.match(regex).slice(1));
}
}
function main() {
const a = new A("Name 1", 20);
const text = a.toString();
const revert = A.fromText(text);
console.log(revert);
}
main();
Remark
If the goal is to serialise and deserialise instances, then it is better not to rely on such human-readable phrases as string representations, but use a format proven for that purpose, like JSON.
So then it would go like this:
class A {
constructor(name, age) {
this.name = name;
this.age = age;
}
toString() {
return `
My name is: ${this.name},
My age is: ${this.age}
`
}
static fromJSON(json) {
return Object.assign(Object.create(this.prototype), JSON.parse(json));
}
}
function main() {
const a = new A("Name 1", 20);
const json = JSON.stringify(a);
const revert = A.fromJSON(json);
console.log(revert);
}
main();

Better Method than using setter in typescript : private variables are declared but value not read issue

I have a scenario like this:
class Employee {
private fullName: string;
private firstName: string;
private lastName: string;
private age: number;
private isValid: boolean;
constructor() {
this.fullName = null;
this.firstName = null;
this.lastName = null;
this.age = null;
this.isValid = false;
}
setfullName(fullName: string) {
this.fullName = fullName;
}
setfirstName(firstName: string) {
this.firstName = firstName;
}
setlastName(lastName: string) {
this.lastName = lastName;
}
setAge(age: number) {
this.age = age;
}
setValid(isValid: boolean) {
this.isValid = isValid;
}
}
// test.ts file
let employee = new Employee();
// set in different positions in test.ts file based on getting the input paramters
employee.setfullName("james cooper");
employee.setfirstName("mary");
employee.setlastName("fransis"); // getting lastName from another api call
employee.setAge(50); // getting 50 from another api call
employee.setValid(true);
Here i am getting a warning in vscode like "private variables are declared but its value is not read".
Inorder to prevent this warning, i have to use getter method, but here purpose is to save the object properties and not reading. So getter method seems to be useless.
Since i am new to typescript, without setting these variables to public or disabling in tslint configuration, can anybody suggest a better approach for the same?
The purpose is to set the employee info, for that I created Employee model.
Any help would be really appreciated.
Thanks in advance
Since you're not doing anything with the data on this side other than assigning to properties of it, it sounds like you should be creating a plain object instead. Since in your original code, all the methods which set properties are public, and don't do anything else, they don't accomplish anything useful. If an external source can call a setter method, it may as well just assign a property directly. The class adds unnecessary and confusing overhead, and part of that is why Typescript is complaining. Instead, do something like:
type Employee = Partial<{
fullName: string;
firstName: string;
lastName: string;
age: number;
isValid: boolean;
}>;
const employee: Employee = {};
employee.age = 15;
employee.isValid = false;
// send employee to front-end
IMO, a class is generally useful only when you need to have data associated with an instance and methods which retrieve and use the data in some way.

How do i create an incrementing array of objects, User1, User2 etc. with object values attached to each entry?

Trying to get an array of temporary users, where next user should be "user" + ArrayOfUsers.length, but i have no idea of how to get there, even after 2 hours of googleing.
Each user in the array should be attached with object values of my standard user defined like this.
function user(name, email, code){
this.name = name;
this.email = email;
this.code = code;
}
Javascript doesn't support declaring variables with dynamic names...But you can assign a dynamic key to a window object (or any other object), and access them as variable names (Only applicable for keys set to window object).
Please note that this won't work in strict mode use strict.
And I'm not sure why you want it as a dynamic variable. Anyways you could do it like below.
You could keep a count variable and set variable to window object using
this["user"+index] = newUser;
Try the below snippet...
function user(name, email, code) {
this.name = name;
this.email = email;
this.code = code;
}
var index = 0;
function createUser(name, email,code){
const newUser = new user(name, email, code);
this["user"+index] = newUser;
index++;
return newUser;
}
createUser("a", "a#a.com", 1);
createUser("b", "b#b.com", 2)
for(let i = 0; i< index; i++){
console.log(this["user"+ i]);
}
console.log(user0);
console.log(user1);

Using classes in for loop in node.js

To be honest, I don't know what to ask for my case so I'll just add some details. I come from java so I am familiar with classes.
Let's take for instance a class and for making it easy, drop the private fields to public and no getter and setter
class User{
public String name;
public String email;
}
This is useful in certain cases, for instance have an array of users and then I can use something like:
for(User user: usersList){
user.name='some new value'
//since user is a class, code assist, suggests the name and also if I have user.namee it throws an error
}
Now moving into javascript, I can obtain an array and do something like
for (let user of usersList){
user.name='some new value'
//however if I type user.nammee no error is thrown and code assist does not know what to recomment
}
I think that now you may get the idea. I want it to make it easier to properly obtain the object fields with code assist and also avoid typing errors because of property name badly typed. Javascript classes from what I see have only methods... so what can I apply in this case?
check out Typescript
and this "fiddle" on the TypeScript Playground
class User {
constructor(public name: string, public email: string = "") { }
/*
//shorthand for
public name: string;
public email: string;
constructor(name:string, email:string="") {
this.name = name;
this.email = email;
}
*/
}
var usersList = [
new User("Jack"),
new User("Jill"),
new User("Joe")
];
for (let user of usersList) {
user.email = user.name + "#mail.com";
}
and since userList is recognized as type User[], let user is also typed as let user:User
JavaScript allows to reference properties which an object does not have: you can add them ad-hoc, and if you read non-existing properties, you just get undefined. This is how JavaScript works.
If you want to get an error when you try to assign to a non-existing property, then consider using the Object.seal method, which you could apply in the constructor for your class:
"use strict";
class User{
constructor (name, email) {
this.name = name;
this.email = email;
// Seal will disallow new properties
Object.seal(this);
}
}
const user = new User();
user.name = "Jeff";
console.log(user); // Shows property with "Jeff"
user.nammmeeee = "Jeff"; // Produces error
Make sure to use strict mode ("use strict") as otherwise these errors are suppressed.
You can do this in javascript. Just that, your userslist will be array in which you will have your users. Loop will be for loop from 0 to length-1. This class will have some syntax like this.
var userclass = {
Name:'xyz',
Addr:'address',
.....other props
}

What exactly happens in .net when a webservice call parses a JSON object?

Suppose I write the following C# code to define a web method:
public class Thing
{
public string X {get;set}
public string Y {get;set}
}
[WebMethod]
public static void myFunction(Thing thing) { }
I've discovered that I can invoke the function using the jQuery JavaScript that looks like this:
var myData = { X: "hello", Y: "world" };
var jsonData = JSON.stringify(myData);
jQuery.ajax({ data: jsonData, ...
When myFunction is thus invoked, thing.X is set to "hello" and thing.Y is set to "world". What exactly does the .net framework do to set the value of thing? Does it invoke a constructor?
Just like you can create Thing like so
Thing x = new Thing { X = "hello", Y = "world" }
So no it does not call the constructor to answer your question.
Ok, more detail...
It takes the JSON and deserializes it. It fills the properties from you JSON object. For example, if you had the following in JSON:
{"notRelated":0, "test": "string"}
The serializer would not find X or Y for thing and set them to the default value for that data type.
Let's say you want to go deeper. You can custom serialize and deserialize your objects:
[Serializable]
public class MyObject : ISerializable
{
public int n1;
public int n2;
public String str;
public MyObject()
{
}
protected MyObject(SerializationInfo info, StreamingContext context)
{
n1 = info.GetInt32("i");
n2 = info.GetInt32("j");
str = info.GetString("k");
}
[SecurityPermissionAttribute(SecurityAction.Demand,SerializationFormatter=true)]
public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("i", n1);
info.AddValue("j", n2);
info.AddValue("k", str);
}
}
So you can see, it's fishing for parameters in your case, X and Y.

Categories

Resources