Object Converter¶
Javet has a built-in JavetObjectConverter
with the following features.
It covers primitive types + Set + Map + Array.
It is completely open to subclass.
It minimizes the performance overhead.
It allows registering custom objects.
From Java to JavaScript¶
Java |
JavaScript |
---|---|
boolean[] |
Array |
byte[] |
Int8Array |
char[] |
Array |
double[] |
Float64Array |
float[] |
Float32Array |
int[] |
Int32Array |
long[] |
Int64Array |
short[] |
Int16Array |
Object[] |
Array |
Map |
object or Proxy |
Set |
Set or Proxy |
Collection |
Array |
Stream |
Array |
IJavetEntityFunction |
Function |
IJavetEntityMap |
Map |
JavetEntitySymbol |
Symbol |
IJavetMappable |
Any |
From JavaScript to Java¶
JavaScript |
Java |
---|---|
Array |
ArrayList<Object> |
Set |
HashSet<Object> |
Map |
HashMap<Object, Object> |
Int8Array |
byte[] |
Uint8Array |
byte[] |
Uint8ClampedArray |
byte[] |
Int16Array |
short[] |
Uint16Array |
short[] |
Int32Array |
int[] |
Uint32Array |
int[] |
Float32Array |
float[] |
Float64Array |
double[] |
BigInt32Array |
long[] |
BigInt64Array |
long[] |
Function |
IJavetEntityFunction |
Symbol |
JavetEntitySymbol |
Proxy |
Any |
Object |
HashMap<Object, Object> or Any |
So, Javet doesn't natively support converting POJO objects because a POJO converter has to deal with reflection which is so slow that Javet leaves that to applications. However, if the POJO objects are owned by the application, it is possible to register custom objects with the built-in JavetObjectConverter
. Otherwise, designing a POJO converter is the alternative solution.
Register Custom Objects¶
JavetObjectConverter
exposes registerCustomObject()
for alien objects which match the following conditions.
Default constructor without arguments
Method with signature
void fromMap(Map<String, Object> map)
Method with signature
Map<String, Object> toMap()
Note
If the target custom object is touchable, having it implement IJavetMappable
can make things easier.
Enhance the Custom Object¶
Create a default constructor without arguments.
Add a method with signature
void fromMap(Map<String, Object> map)
Add a method with signature
Map<String, Object> toMap()
Can the method names be changed? Yes, they can have arbitrary names.
public final class CustomObject {
private String name;
private int value;
public CustomObject(String name, int value) {
this.name = name;
this.value = value;
}
public CustomObject() {
this(null, 0);
}
public void fromMap(Map<String, Object> map) {
setName((String) map.get("name"));
setValue((Integer) map.get("value"));
}
public Map<String, Object> toMap() {
return new HashMap<String, Object>() {
{
put("name", getName());
put("value", getValue());
}
};
}
// getters and setters
}
Register the Custom Object¶
As the default converter is JavetObjectConverter
, just follow the code snippet below to register a custom object.
JavetObjectConverter converter = (JavetObjectConverter)v8Runtime.getConverter();
converter.registerCustomObject(CustomObject.class);
If the method names are different from the default ones, just provide the names upon registration as the following.
converter.registerCustomObject(CustomObject.class, "customFromMap", "customToMap");
Usage¶
After the registration is completed, there is no additional steps any more. Just follow the regular pattern.
CustomObject[] customObjects = new CustomObject[]{
new CustomObject("x", 1),
new CustomObject("y", 2),
};
v8Runtime.getGlobalObject().set("a", customObjects);
assertEquals(2, v8Runtime.getExecutor("a.length").executeInteger());
List<CustomObject> v8CustomObjects = v8Runtime.getGlobalObject().getObject("a");
assertNotNull(v8CustomObjects);
assertEquals(2, v8CustomObjects.size());
for (int i = 0; i < customObjects.length; i++) {
assertEquals(customObjects[i].getName(), v8Runtime.getExecutor("a[" + i + "].name").executeString());
assertEquals(customObjects[i].getValue(), v8Runtime.getExecutor("a[" + i + "].value").executeInteger());
assertEquals(customObjects[i].getName(), v8CustomObjects.get(i).getName());
assertEquals(customObjects[i].getValue(), v8CustomObjects.get(i).getValue());
}
Highlights¶
PROS: This is a built-in feature so there is no need to deal with a POJO converter.
CONS: This is a little bit intrusive to the custom objects.
How does It Work?¶
As V8 supports private properties, JavetObjectConverter
sets the custom object class name to the V8 object in toMap()
and gets the name from the V8 object in fromMap()
. So it is the V8 object that carries the type information all the time and JavetObjectConverter
is free from memorizing the complicated relationship between the Java objects and V8 objects.