public final class JavaInterop extends Object
Truffle languages from
Java and the other way around. The Java/Truffle interop builds on
mutual interoperability between individual Truffle languages - it
just encapsulates it into Java facade to make it as natural to access foreign
Truffle objects as Java programmers are used to when accessing
Java objects and interfaces directly.
TruffleObject implementation, and somebody wraps your
object into a JavaInterop interface via
JavaInterop.asJavaObject(java.lang.Class, com.oracle.truffle.api.interop.TruffleObject) method, this
is the set of messages you can expect:
Users can send you any message by annotating their interface method with MethodMessage
and it is up to them (and you) to negotiate the correct set of messages and their parameters to
help you understand each other. However there is a default set of messages (for
methods not annotated by MethodMessage) which consists of:
Message.createInvoke(int) is constructed (with the number of parameters
of the interface method) and delivered to your object. The
receiver of the message is
your TruffleObject. The first
argument is name of the
interface method, followed by the
actual arguments of the
interface method. Your language can either handle the message or throw
UnsupportedMessageException to signal additional processing is needed.previous message isn't handled, a
Message.READ is sent to your object (e.g.
receiver) with a field name
equal to the name of the interface method. If the read returns a primitive type, it is returned.
TruffleObject, it is inspected whether it handles
Message.IS_EXECUTABLE. If it does, a message Message.createExecute(int) with name
of the interface method and its parameters is sent to the object. The result is returned to the
interface method caller.executable
, and the interface method has no parameters, it is returned back.InteropException.
Object oriented languages are expected to handle the initial Message.createInvoke(int)
message. Non-OOP languages are expected to ignore it, yield UnsupportedMessageException
and handle the subsequent read and execute ones. The real semantic however depends on the actual language one is communicating
with.
PolyglotEngine you can use
PolyglotEngine.Builder.globalSymbol(java.lang.String, java.lang.Object) method to create references
to classes with static methods and fields or instance methods or fields as shown in following
example:
public static final class Multiplier {
public static int mul(int x, int y) {
return x * y;
}
}
public interface Multiply {
int mul(int x, int y);
}
public static PolyglotEngine configureJavaInterop(Multiply multiply) {
TruffleObject staticAccess = JavaInterop.asTruffleObject(Multiplier.class);
TruffleObject instanceAccess = JavaInterop.asTruffleObject(multiply);
PolyglotEngine engine = PolyglotEngine.newBuilder().
globalSymbol("mul", staticAccess).
globalSymbol("compose", instanceAccess).
build();
return engine;
}
After that objects mul and compose are available for import from any
Truffe language.| Modifier and Type | Method and Description |
|---|---|
static <T> T |
asJavaFunction(Class<T> functionalType,
TruffleObject function)
Takes executable object from a
TruffleLanguage and converts it into an instance of a
Java functional interface. |
static <T> T |
asJavaObject(Class<T> type,
TruffleObject foreignObject)
Wraps a
foreign object into easy to use interface. |
static <T> TruffleObject |
asTruffleFunction(Class<T> functionalType,
T implementation)
Takes a functional interface and its implementation (for example lambda function) and
converts it into object executable by Truffle languages.
|
static TruffleObject |
asTruffleObject(Object obj)
Exports a Java object for use in any
TruffleLanguage. |
static Object |
asTruffleValue(Object obj)
Prepares a Java object for use in any
TruffleLanguage. |
static int |
getKeyInfo(TruffleObject foreignObject,
Object propertyName)
Get information about an object property.
|
static <K,V> Map<K,V> |
getMapView(Map<K,V> map,
boolean includeInternal)
Get a view of map created by
JavaInterop.asJavaObject(java.lang.Class, com.oracle.truffle.api.interop.TruffleObject) with
as an argument. |
static boolean |
isArray(TruffleObject foreignObject)
Test whether the object represents an array.
|
static boolean |
isBoxed(TruffleObject foreignObject)
Test whether the object represents a boxed primitive type.
|
static boolean |
isJavaObject(Class<?> type,
TruffleObject foreignObject)
Checks whether an
object is a Java object of a given type. |
static boolean |
isNull(TruffleObject foreignObject)
Test whether the object represents a
null value. |
static boolean |
isPrimitive(Object obj)
Test whether the object is a primitive, which all
TruffleLanguages are supposed to
handle. |
static TruffleObject |
toJavaClass(TruffleObject obj)
Finds a Java class representation for the provided object.
|
static Object |
unbox(TruffleObject foreignObject)
Convert the object into a Java primitive type.
|
public static <T> T asJavaObject(Class<T> type, TruffleObject foreignObject)
foreign object into easy to use interface. Imagine one wants to
access a JavaScript object like:
var obj = {
'x' : 10,
'y' : 3.3,
'name' : 'Truffle'
};
from Java. One can do it by defining an interface:
interface ObjAccess {
int x();
@MethodMessage(message = "WRITE")
void x(int newValue);
double y();
String name();
}
and obtaining its instance by calling this conversion method:
ObjAccess access = JavaInterop.asJavaObject(ObjAccess.class, obj);
assert access.x() == 10 : "Still the default";
access.x(5);
assert access.x() == 5 : "Changed to five";
T - type of requested and returned valuetype - interface modeling structure of foreignObject in JavaforeignObject - object coming from a Truffle language, can be
null, in such case the returned value will likely be
null as wellforeignObject, can be null, if the foreignObject parameter
was nullClassCastException - if the foreignObject cannot be converted to
requested typepublic static boolean isJavaObject(Class<?> type, TruffleObject foreignObject)
object is a Java object of a given type.
Given some Java object x of type X, the following assertion will
always pass.
X x = ...; TruffleObject obj = JavaInterop.asTruffleObject(x); assert JavaInterop.isJavaObject(X.class, obj);
type - Java class that the object is tested forforeignObject - object coming from a Truffle languagetrue if the foreignObject was created from an object of class
type using JavaInterop.asTruffleObject(Object), false otherwisepublic static TruffleObject asTruffleObject(Object obj)
TruffleLanguage. The system scans structure of
provided object and exposes all public fields and methods to any Truffle
language. An instance of class
class JavaRecord {
public int x;
public double y;
public String name() {
return "Truffle";
}
}
TruffleObject obj = JavaInterop.asTruffleObject(new JavaRecord());
can then be access from JavaScript or any other Truffle based language as
obj.x; obj.y; obj.name();
One can also enumerate the properties of the object and see all three of them:
for (var p in obj) {
print(p); // yields x, y, name
}
When the obj represents a Class, then the created TruffleObject
will allow access to public and static fields and methods from the class.
Do not convert primitive types (instances of Number, Boolean,
Character or String) to TruffleObject, all TruffleLanguages
are supposed to handle primitives. Use directly the the primitive types instead. To convert
generic objects to TruffleObject while retaining primitive values unwrapped, use
JavaInterop.asTruffleValue(java.lang.Object) instead.
obj - a Java object to convert into one suitable for Truffle languagespublic static Object asTruffleValue(Object obj)
TruffleLanguage. If the object is one of
primitive values, it is just returned, as all TruffleLanguages
are supposed to handle such object. If it is a non-primitive type of Java object, the method
does exactly the same thing as JavaInterop.asTruffleObject(java.lang.Object).obj - a Java object to convert into one suitable for Truffle languagespublic static boolean isPrimitive(Object obj)
TruffleLanguages are supposed to
handle. Primitives are instances of Number, Boolean, Character or
String.obj - a Java object to testtrue when the object is a primitive from TruffleLanguages point
of view, false otherwise.public static <T> T asJavaFunction(Class<T> functionalType, TruffleObject function)
TruffleLanguage and converts it into an instance of a
Java functional interface. If the functionalType method is using
variable arguments, then the arguments are unwrapped and passed
into the function as indivual arguments.T - requested and returned typefunctionalType - interface with a single defined method - so called functional
interfacefunction - Truffle that responds to Message.IS_EXECUTABLE and can be
invokedfunctionpublic static <T> TruffleObject asTruffleFunction(Class<T> functionalType, T implementation)
TruffleObject to = JavaInterop.asTruffleFunction(Callable.class, () -> 42);
Callable c = JavaInterop.asJavaFunction(Callable.class, to);
assert c.call() == 42;
T - requested interface and implementationfunctionalType - interface with a single defined method - so called functional
interfaceimplementation - implementation of the interface, or directly a lambda expression
defining the required behaviorexecutable TruffleObject ready to be used in
any Truffle languagepublic static boolean isNull(TruffleObject foreignObject)
null value.foreignObject - object coming from a Truffle language, can be
null.true when the object represents a null value,
false otherwise.Message.IS_NULLpublic static boolean isArray(TruffleObject foreignObject)
asJavaObject(java.util.List.class, foreignObject);
foreignObject - object coming from a Truffle language, can be
null.true when the object represents an array, false otherwise.Message.HAS_SIZEpublic static boolean isBoxed(TruffleObject foreignObject)
foreignObject - object coming from a Truffle language, can be
null.true when the object represents a boxed primitive type,
false otherwise.Message.IS_BOXEDpublic static Object unbox(TruffleObject foreignObject)
foreignObject - object coming from a Truffle language, which is
known (check JavaInterop.isBoxed(com.oracle.truffle.api.interop.TruffleObject)) to be
a boxed Java primitive type.null when the
unboxing was not possible.Message.UNBOXpublic static int getKeyInfo(TruffleObject foreignObject, Object propertyName)
foreignObject - object coming from a Truffle languagepropertyName - name of a property or index of an arrayKeyInfo bit flags.Message.KEY_INFO,
KeyInfopublic static <K,V> Map<K,V> getMapView(Map<K,V> map, boolean includeInternal) throws IllegalArgumentException
JavaInterop.asJavaObject(java.lang.Class, com.oracle.truffle.api.interop.TruffleObject) with
Map.class as an argument. The view includes or excludes
internal elements based on includeInternal
parameter.map - a map obtained by
JavaInterop.asJavaObject(java.lang.Class, com.oracle.truffle.api.interop.TruffleObject)includeInternal - true to include internal elements in the map,
false to exclude them.includeInternal argument.IllegalArgumentException - when the Map was not created by
JavaInterop.asJavaObject(java.lang.Class, com.oracle.truffle.api.interop.TruffleObject)
.public static TruffleObject toJavaClass(TruffleObject obj)
asTruffleObject(original) call, then it is
unwrapped and the result is equal to asTruffleObject(original.getClass()).
This method works only on objects that wrap plain Java objects.
obj - object expected to be created by JavaInterop.asTruffleObject(java.lang.Object) or
similar methodswrapper around
original Java object's type if any. Otherwise
null