All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.graalvm.polyglot.Value Maven / Gradle / Ivy

/*
 * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * The Universal Permissive License (UPL), Version 1.0
 *
 * Subject to the condition set forth below, permission is hereby granted to any
 * person obtaining a copy of this software, associated documentation and/or
 * data (collectively the "Software"), free of charge and under any and all
 * copyright rights in the Software, and any and all patent rights owned or
 * freely licensable by each licensor hereunder covering either (i) the
 * unmodified Software as contributed to or provided by such licensor, or (ii)
 * the Larger Works (as defined below), to deal in both
 *
 * (a) the Software, and
 *
 * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
 * one is included with the Software each a "Larger Work" to which the Software
 * is contributed by such licensors),
 *
 * without restriction, including without limitation the rights to copy, create
 * derivative works of, display, perform, and distribute the Software and make,
 * use, sell, offer for sale, import, export, have made, and have sold the
 * Software and the Larger Work(s), and to sublicense the foregoing rights on
 * either these or other terms.
 *
 * This license is subject to the following condition:
 *
 * The above copyright notice and either this complete permission notice or at a
 * minimum a reference to the UPL must be included in all copies or substantial
 * portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package org.graalvm.polyglot;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.zone.ZoneRules;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;

import org.graalvm.polyglot.HostAccess.TargetMappingPrecedence;
import org.graalvm.polyglot.impl.AbstractPolyglotImpl.AbstractValueImpl;
import org.graalvm.polyglot.proxy.Proxy;

/**
 * Represents a polyglot value that can be accessed using a set of language agnostic operations.
 * Polyglot values represent values from {@link #isHostObject() host} or guest language. Polyglot
 * values are bound to a {@link Context context}. If the context is closed then all value operations
 * throw an {@link IllegalStateException}.
 * 

* Polyglot values have one of the following type combinations: *

    *
  • {@link #isNull() Null}: This value represents a null like value. Certain * languages might use a different name or use multiple values to represent null like * values. *
  • {@link #isNumber() Number}: This value represents a floating or fixed point number. The * number value may be accessed as {@link #asByte() byte}, {@link #asShort() short} {@link #asInt() * int} {@link #asLong() long}, {@link #asFloat() float} or {@link #asDouble() double} value. *
  • {@link #isBoolean() Boolean}. This value represents a boolean value. The boolean value can be * accessed using {@link #asBoolean()}. *
  • {@link #isString() String}: This value represents a string value. The string value can be * accessed using {@link #asString()}. *
  • {@link #isDate() Date}, {@link #isTime() Time} or {@link #isTimeZone() Timezone}: This value * represents a date, time or timezone. Multiple types may return true at the same * time. *
  • {@link #isDuration() Duration}: This value represents a duration value. The duration value * can be accessed using {@link #asDuration()}. *
  • {@link #isHostObject() Host Object}: This value represents a value of the host language * (Java). The original Java value can be accessed using {@link #asHostObject()}. *
  • {@link #isProxyObject() Proxy Object}: This value represents a {@link Proxy proxy} value. *
  • {@link #isNativePointer() Native Pointer}: This value represents a native pointer. The native * pointer value can be accessed using {@link #asNativePointer()}. *
  • {@link #isException() Exception}: This value represents an exception object. The exception * can be thrown using {@link #throwException()}. *
  • {@link #isMetaObject() Meta-Object}: This value represents a metaobject. Access metaobject * operations using {@link #getMetaSimpleName()}, {@link #getMetaQualifiedName()} and * {@link #isMetaInstance(Object)}. *
* In addition any value may have one or more of the following traits: *
    *
  • {@link #hasArrayElements() Array Elements}: This value may contain array elements. The array * indices always start with 0, also if the language uses a different style. *
  • {@link #hasMembers() Members}: This value may contain members. Members are structural * elements of an object. For example, the members of a Java object are all public methods and * fields. Members are accessible using {@link #getMember(String)}. *
  • {@link #canExecute() Executable}: This value can be {@link #execute(Object...) executed}. * This indicates that the value represents an element that can be executed. Guest language examples * for executable elements are functions, methods, closures or promises. *
  • {@link #canInstantiate() Instantiable}: This value can be {@link #newInstance(Object...) * instantiated}. For example, Java classes are instantiable. *
*

* In addition to the language agnostic types, the language specific type can be accessed using * {@link #getMetaObject()}. The identity of value objects is unspecified and should not be relied * upon. For example, multiple calls to {@link #getArrayElement(long)} with the same index might * return the same or different instances of {@link Value}. The {@link #equals(Object) equality} of * values is based on the identity of the value instance. All values return a human-readable * {@link #toString() string} for debugging, formatted by the original language. *

* Polyglot values may be converted to host objects using {@link #as(Class)}. In addition values may * be created from Java values using {@link Context#asValue(Object)}. * *

Naive and aware dates and times

*

* If a date or time value has a {@link #isTimeZone() timezone} then it is called aware, * otherwise naive. *

* An aware time and date has sufficient knowledge of applicable algorithmic and political time * adjustments, such as time zone and daylight saving time information, to locate itself relative to * other aware objects. An aware object is used to represent a specific moment in time that is not * open to interpretation. *

* A naive time and date does not contain enough information to unambiguously locate itself relative * to other date/time objects. Whether a naive object represents Coordinated Universal Time (UTC), * local time, or time in some other timezone is purely up to the program, just like it is up to the * program whether a particular number represents metres, miles, or mass. Naive objects are easy to * understand and to work with, at the cost of ignoring some aspects of reality. * * @see Context * @see Engine * @see PolyglotException * @since 19.0 */ public final class Value { final Object receiver; final AbstractValueImpl impl; Value(AbstractValueImpl impl, Object value) { this.impl = impl; this.receiver = value; } /** * Returns the metaobject that is associated with this value or null if no * metaobject is available. The metaobject represents a description of the object, reveals it's * kind and it's features. Some information that a metaobject might define includes the base * object's type, interface, class, methods, attributes, etc. *

* The returned value returns true for {@link #isMetaObject()} and provides * implementations for {@link #getMetaSimpleName()}, {@link #getMetaQualifiedName()}, and * {@link #isMetaInstance(Object)}. *

* This method does not cause any observable side-effects. * * @throws IllegalStateException if the context is already closed. * @throws PolyglotException if a guest language error occurred during execution. * @see #isMetaObject() * @since 19.0 revised in 20.1 */ public Value getMetaObject() { return impl.getMetaObject(receiver); } /** * Returns true if the value represents a metaobject. Metaobjects may be values * that naturally occur in a language or they may be returned by {@link #getMetaObject()}. A * metaobject represents a description of the object, reveals its kind and its features. Returns * false by default. Metaobjects are often also {@link #canInstantiate() * instantiable}, but not necessarily. *

* Sample interpretations: In Java an instance of the type {@link Class} is a metaobject. * In JavaScript any function instance is a metaobject. For example, the metaobject of a * JavaScript class is the associated constructor function. *

* This method does not cause any observable side-effects. If this method is implemented then * also {@link #getMetaQualifiedName()}, {@link #getMetaSimpleName()} and * {@link #isMetaInstance(Object)} must be implemented as well. * * @throws IllegalStateException if the context is already closed. * @throws PolyglotException if a guest language error occurred during execution. * @see #getMetaQualifiedName() * @see #getMetaSimpleName() * @see #isMetaInstance(Object) * @see #getMetaObject() * @since 20.1 */ public boolean isMetaObject() { return impl.isMetaObject(receiver); } /** * Returns the qualified name of a metaobject as {@link #isString() String}. *

* Sample interpretations: The qualified name of a Java class includes the package name * and its class name. JavaScript does not have the notion of qualified name and therefore * returns the {@link #getMetaSimpleName() simple name} instead. * * @throws UnsupportedOperationException if and only if {@link #isMetaObject()} returns * false for the same value. * @throws PolyglotException if a guest language error occurred during execution. * @since 20.1 */ public String getMetaQualifiedName() { return impl.getMetaQualifiedName(receiver); } /** * Returns the simple name of a metaobject as {@link #isString() string}. *

* Sample interpretations: The simple name of a Java class is the class name. * * @throws UnsupportedOperationException if and only if {@link #isMetaObject()} returns * false for the same value. * @throws PolyglotException if a guest language error occurred during execution. * @since 20.1 */ public String getMetaSimpleName() { return impl.getMetaSimpleName(receiver); } /** * Returns true if the given instance is an instance of this value, else * false. The instance value is subject to polyglot value mapping rules as * described in {@link Context#asValue(Object)}. *

* Sample interpretations: A Java object is an instance of its returned * {@link Object#getClass() class}. *

* * @param instance the instance object to check. * @throws UnsupportedOperationException if and only if {@link #isMetaObject()} returns * false for the same value. * @throws PolyglotException if a guest language error occurred during execution. * @since 20.1 */ public boolean isMetaInstance(Object instance) { return impl.isMetaInstance(receiver, instance); } /** * Returns true if this polyglot value has array elements. In this case array * elements can be accessed using {@link #getArrayElement(long)}, * {@link #setArrayElement(long, Object)}, {@link #removeArrayElement(long)} and the array size * can be queried using {@link #getArraySize()}. * * @throws IllegalStateException if the context is already closed. * @throws PolyglotException if a guest language error occurred during execution. * @since 19.0 */ public boolean hasArrayElements() { return impl.hasArrayElements(receiver); } /** * Returns the array element of a given index. Polyglot arrays start with index 0, * independent of the guest language. The given array index must be greater or equal to 0. * * @throws ArrayIndexOutOfBoundsException if the array index does not exist. * @throws UnsupportedOperationException if the value does not have any * {@link #hasArrayElements() array elements} or if the index exists but is not * readable. * @throws IllegalStateException if the context is already closed. * @throws PolyglotException if a guest language error occurred during execution. * @since 19.0 */ public Value getArrayElement(long index) { return impl.getArrayElement(receiver, index); } /** * Sets the value at a given index. Polyglot arrays start with index 0, independent * of the guest language. The array element value is subject to polyglot value mapping rules as * described in {@link Context#asValue(Object)}. * * @throws ArrayIndexOutOfBoundsException if the array index does not exist. * @throws UnsupportedOperationException if the value does not have any * {@link #hasArrayElements() array elements} or if the index exists but is not * modifiable. * @throws IllegalStateException if the context is already closed. * @throws PolyglotException if a guest language error occurred during execution. * @since 19.0 */ public void setArrayElement(long index, Object value) { impl.setArrayElement(receiver, index, value); } /** * Removes an array element at a given index. Returns true if the underlying array * element could be removed, otherwise false. * * @throws ArrayIndexOutOfBoundsException if the array index does not exist. * @throws UnsupportedOperationException if the value does not have any * {@link #hasArrayElements() array elements} or if the index exists but is not * removable. * @throws IllegalStateException if the context is already closed. * @throws PolyglotException if a guest language error occurred during execution. * @since 19.0 */ public boolean removeArrayElement(long index) { return impl.removeArrayElement(receiver, index); } /** * Returns the array size for values with array elements. * * @throws UnsupportedOperationException if the value does not have any * {@link #hasArrayElements() array elements}. * @throws IllegalStateException if the context is already closed. * @throws PolyglotException if a guest language error occurred during execution. * @since 19.0 */ public long getArraySize() { return impl.getArraySize(receiver); } /** * Returns true if this value generally supports containing members. To check * whether a value has no members use * {@link #getMemberKeys() getMemberKeys()}.{@link Set#isEmpty() isEmpty()} * instead. If polyglot value has members, it may also support {@link #getMember(String)}, * {@link #putMember(String, Object)} and {@link #removeMember(String)}. * * @see #hasMember(String) To check the existence of members. * @see #getMember(String) To read members. * @see #putMember(String, Object) To write members. * @see #removeMember(String) To remove a member. * @see #getMemberKeys() For a list of members. * @throws IllegalStateException if the context is already closed. * @throws PolyglotException if a guest language error occurred during execution. * @since 19.0 */ public boolean hasMembers() { return impl.hasMembers(receiver); } /** * Returns true if such a member exists for a given identifier. If the * value has no {@link #hasMembers() members} then {@link #hasMember(String)} returns * false. * * @throws PolyglotException if a guest language error occurred during execution. * @throws NullPointerException if the identifier is null. * @since 19.0 */ public boolean hasMember(String identifier) { Objects.requireNonNull(identifier, "identifier"); return impl.hasMember(receiver, identifier); } /** * Returns the member with a given identifier or null if the member * does not exist. * * @throws UnsupportedOperationException if the value {@link #hasMembers() has no members} or * the given identifier exists but is not readable. * @throws PolyglotException if a guest language error occurred during execution. * @throws NullPointerException if the identifier is null. * @since 19.0 */ public Value getMember(String identifier) { Objects.requireNonNull(identifier, "identifier"); return impl.getMember(receiver, identifier); } /** * Returns a set of all member keys. Calling {@link Set#contains(Object)} with a string key is * equivalent to calling {@link #hasMember(String)}. Removing an element from the returned set * is equivalent to calling {@link #removeMember(String)}. Adding an element to the set is * equivalent to calling {@linkplain #putMember(String, Object) putMember(key, null)}. If the * value does not support {@link #hasMembers() members} then an empty unmodifiable set is * returned. If the context gets closed while the returned set is still alive, then the set will * throw an {@link IllegalStateException} if any methods except Object methods are invoked. * * @throws IllegalStateException if the context is already {@link Context#close() closed}. * @throws PolyglotException if a guest language error occurred during execution. * @since 19.0 */ public Set getMemberKeys() { return impl.getMemberKeys(receiver); } /** * Sets the value of a member using an identifier. The member value is subject to polyglot value * mapping rules as described in {@link Context#asValue(Object)}. * * @throws IllegalStateException if the context is already {@link Context#close() closed}. * @throws UnsupportedOperationException if the value does not have any {@link #hasMembers() * members}, the key does not exist and new members cannot be added, or the existing * member is not modifiable. * @throws PolyglotException if a guest language error occurred during execution. * @throws NullPointerException if the identifier is null. * @since 19.0 */ public void putMember(String identifier, Object value) { Objects.requireNonNull(identifier, "identifier"); impl.putMember(receiver, identifier, value); } /** * Removes a single member from the object. Returns true if the member was * successfully removed, false if such a member does not exist. * * @throws UnsupportedOperationException if the value does not have any {@link #hasMembers() * members} or if the key {@link #hasMember(String) exists} but cannot be removed. * @throws IllegalStateException if the context is already {@link Context#close() closed}. * @throws PolyglotException if a guest language error occurred during execution. * @throws NullPointerException if the identifier is null. * @since 19.0 */ public boolean removeMember(String identifier) { Objects.requireNonNull(identifier, "identifier"); return impl.removeMember(receiver, identifier); } // executable /** * Returns true if the value can be {@link #execute(Object...) executed}. * * @throws IllegalStateException if the underlying context was closed. * @see #execute(Object...) * @since 19.0 */ public boolean canExecute() { return impl.canExecute(receiver); } /** * Executes this value if it {@link #canExecute() can} be executed and returns its result. If no * result value is expected or needed use {@link #executeVoid(Object...)} for better * performance. All arguments are subject to polyglot value mapping rules as described in * {@link Context#asValue(Object)}. * * @throws IllegalStateException if the underlying context was closed. * @throws IllegalArgumentException if a wrong number of arguments was provided or one of the * arguments was not applicable. * @throws UnsupportedOperationException if this value cannot be executed. * @throws PolyglotException if a guest language error occurred during execution. * @throws NullPointerException if the arguments array is null. * @see #executeVoid(Object...) * @since 19.0 */ public Value execute(Object... arguments) { if (arguments.length == 0) { // specialized entry point for zero argument execute calls return impl.execute(receiver); } else { return impl.execute(receiver, arguments); } } /** * Executes this value if it {@link #canExecute() can} be executed. All arguments are subject to * polyglot value mapping rules as described in {@link Context#asValue(Object)}. * * @throws IllegalStateException if the underlying context was closed. * @throws IllegalArgumentException if a wrong number of arguments was provided or one of the * arguments was not applicable. * @throws UnsupportedOperationException if this value cannot be executed. * @throws PolyglotException if a guest language error occurred during execution. * @throws NullPointerException if the arguments array is null. * @see #execute(Object...) * @since 19.0 */ public void executeVoid(Object... arguments) { if (arguments.length == 0) { // specialized entry point for zero argument execute calls impl.executeVoid(receiver); } else { impl.executeVoid(receiver, arguments); } } /** * Returns true if the value can be instantiated. This indicates that the * {@link #newInstance(Object...)} can be used with this value. If a value is instantiable it is * often also a {@link #isMetaObject()}, but this is not a requirement. * * @see #isMetaObject() * @since 19.0 */ public boolean canInstantiate() { return impl.canInstantiate(receiver); } /** * Instantiates this value if it {@link #canInstantiate() can} be instantiated. All arguments * are subject to polyglot value mapping rules as described in {@link Context#asValue(Object)}. * * @throws IllegalStateException if the underlying context was closed. * @throws IllegalArgumentException if a wrong number of arguments was provided or one of the * arguments was not applicable. * @throws UnsupportedOperationException if this value cannot be instantiated. * @throws PolyglotException if a guest language error occurred during execution. * @throws NullPointerException if the arguments array is null. * @since 19.0 */ public Value newInstance(Object... arguments) { Objects.requireNonNull(arguments, "arguments"); return impl.newInstance(receiver, arguments); } /** * Returns true if the given member exists and can be invoked. Returns * false if the member does not exist ({@link #hasMember(String)} returns * false), or is not invocable. * * @param identifier the member identifier * @throws IllegalStateException if the context is already closed. * @throws PolyglotException if a guest language error occurred. * @see #getMemberKeys() For a list of members. * @see #invokeMember(String, Object...) * @since 19.0 */ public boolean canInvokeMember(String identifier) { Objects.requireNonNull(identifier, "identifier"); return impl.canInvoke(identifier, receiver); } /** * Invokes the given member of this value. Unlike {@link #execute(Object...)}, this is an object * oriented execution of a member of an object. To test whether invocation is supported, call * {@link #canInvokeMember(String)}. When object oriented semantics are not supported, use * {@link #getMember(String)}.{@link #execute(Object...) execute(Object...)} * instead. * * @param identifier the member identifier to invoke * @param arguments the invocation arguments * @throws UnsupportedOperationException if this member cannot be invoked. * @throws PolyglotException if a guest language error occurred during invocation. * @throws NullPointerException if the arguments array is null. * @see #canInvokeMember(String) * @since 19.0 */ public Value invokeMember(String identifier, Object... arguments) { Objects.requireNonNull(identifier, "identifier"); if (arguments.length == 0) { // specialized entry point for zero argument invoke calls return impl.invoke(receiver, identifier); } else { return impl.invoke(receiver, identifier, arguments); } } /** * Returns true if this value represents a string. * * @throws PolyglotException if a guest language error occurred during execution. * @throws IllegalStateException if the underlying context was closed. * @since 19.0 */ public boolean isString() { return impl.isString(receiver); } /** * Returns the {@link String} value if this value {@link #isString() is} a string. This method * returns null if this value represents a {@link #isNull() null} value. * * @throws ClassCastException if this value could not be converted to string. * @throws UnsupportedOperationException if this value does not represent a string. * @throws PolyglotException if a guest language error occurred during execution. * @since 19.0 */ public String asString() { return impl.asString(receiver); } /** * Returns true if this value represents a {@link #isNumber() number} and the value * fits in int, else false. * * @throws PolyglotException if a guest language error occurred during execution. * @throws IllegalStateException if the underlying context was closed. * @see #asInt() * @since 19.0 */ public boolean fitsInInt() { return impl.fitsInInt(receiver); } /** * Returns an int representation of this value if it is {@link #isNumber() number} * and the value {@link #fitsInInt() fits}. * * @throws NullPointerException if this value represents {@link #isNull() null}. * @throws ClassCastException if this value could not be converted. * @throws PolyglotException if a guest language error occurred during execution. * @throws IllegalStateException if the underlying context was closed. * @since 19.0 */ public int asInt() { return impl.asInt(receiver); } /** * Returns true if this value represents a boolean value. * * @throws PolyglotException if a guest language error occurred during execution. * @throws IllegalStateException if the underlying context was closed. * @see #asBoolean() * @since 19.0 */ public boolean isBoolean() { return impl.isBoolean(receiver); } /** * Returns a boolean representation of this value if it is {@link #isBoolean() * boolean}. * * @throws NullPointerException if this value represents {@link #isNull() null} * @throws ClassCastException if this value could not be converted. * @throws PolyglotException if a guest language error occurred during execution. * @throws IllegalStateException if the underlying context was closed. * @since 19.0 */ public boolean asBoolean() { return impl.asBoolean(receiver); } /** * Returns true if this value represents a {@link #isNumber() number}, else * false. The number value may be accessed as {@link #asByte() byte}, * {@link #asShort() short} {@link #asInt() int} {@link #asLong() long}, {@link #asFloat() * float} or {@link #asDouble() double} value. * * @throws PolyglotException if a guest language error occurred during execution. * @throws IllegalStateException if the underlying context was closed. * @since 19.0 */ public boolean isNumber() { return impl.isNumber(receiver); } /** * Returns true if this value represents a {@link #isNumber() number} and the value * fits in long, else false. * * @throws PolyglotException if a guest language error occurred during execution. * @throws IllegalStateException if the underlying context was closed. * @see #asLong() * @since 19.0 */ public boolean fitsInLong() { return impl.fitsInLong(receiver); } /** * Returns a long representation of this value if it is {@link #isNumber() number} * and the value {@link #fitsInLong() fits}. * * @throws NullPointerException if this value represents {@link #isNull() null}. * @throws ClassCastException if this value could not be converted to long. * @throws PolyglotException if a guest language error occurred during execution. * @throws IllegalStateException if the underlying context was closed. * @since 19.0 */ public long asLong() { return impl.asLong(receiver); } /** * Returns true if this value represents a {@link #isNumber() number} and the value * fits in double, else false. * * @throws PolyglotException if a guest language error occurred during execution. * @throws IllegalStateException if the underlying context was closed. * @see #asDouble() * @since 19.0 */ public boolean fitsInDouble() { return impl.fitsInDouble(receiver); } /** * Returns a double representation of this value if it is {@link #isNumber() * number} and the value {@link #fitsInDouble() fits}. * * @throws NullPointerException if this value represents {@link #isNull() null}. * @throws ClassCastException if this value could not be converted. * @throws PolyglotException if a guest language error occurred during execution. * @throws IllegalStateException if the underlying context was closed. * @since 19.0 */ public double asDouble() { return impl.asDouble(receiver); } /** * Returns true if this value represents a {@link #isNumber() number} and the value * fits in float, else false. * * @throws PolyglotException if a guest language error occurred during execution. * @throws IllegalStateException if the underlying context was closed. * @see #asFloat() * @since 19.0 */ public boolean fitsInFloat() { return impl.fitsInFloat(receiver); } /** * Returns a float representation of this value if it is {@link #isNumber() number} * and the value {@link #fitsInFloat() fits}. * * @throws NullPointerException if this value represents {@link #isNull() null}. * @throws ClassCastException if this value could not be converted. * @throws PolyglotException if a guest language error occurred during execution. * @throws IllegalStateException if the underlying context was closed. * @since 19.0 */ public float asFloat() { return impl.asFloat(receiver); } /** * Returns true if this value represents a {@link #isNumber() number} and the value * fits in byte, else false. * * @throws PolyglotException if a guest language error occurred during execution. * @throws IllegalStateException if the underlying context was closed. * @see #asByte() * @since 19.0 */ public boolean fitsInByte() { return impl.fitsInByte(receiver); } /** * Returns a byte representation of this value if it is {@link #isNumber() number} * and the value {@link #fitsInByte() fits}. * * @throws NullPointerException if this value represents {@link #isNull() null}. * @throws ClassCastException if this value could not be converted. * @throws PolyglotException if a guest language error occurred during execution. * @throws IllegalStateException if the underlying context was closed. * @since 19.0 */ public byte asByte() { return impl.asByte(receiver); } /** * Returns true if this value represents a {@link #isNumber() number} and the value * fits in short, else false. * * @throws PolyglotException if a guest language error occurred during execution. * @throws IllegalStateException if the underlying context was closed. * @see #asShort() * @since 19.0 */ public boolean fitsInShort() { return impl.fitsInShort(receiver); } /** * Returns a short representation of this value if it is {@link #isNumber() number} * and the value {@link #fitsInShort() fits}. * * @throws NullPointerException if this value represents {@link #isNull() null}. * @throws ClassCastException if this value could not be converted. * @throws PolyglotException if a guest language error occurred during execution. * @throws IllegalStateException if the underlying context was closed. * @since 19.0 */ public short asShort() { return impl.asShort(receiver); } /** * Returns true if this value is a null like. * * @throws PolyglotException if a guest language error occurred during execution. * @throws IllegalStateException if the underlying context was closed. * @since 19.0 */ public boolean isNull() { return impl.isNull(receiver); } /** * Returns true if this value is a native pointer. The value of the pointer can be * accessed using {@link #asNativePointer()}. * * @throws PolyglotException if a guest language error occurred during execution. * @throws IllegalStateException if the underlying context was closed. * @since 19.0 */ public boolean isNativePointer() { return impl.isNativePointer(receiver); } /** * Returns the value of the pointer as long value. * * @throws UnsupportedOperationException if the value is not a pointer. * @throws PolyglotException if a guest language error occurred during execution. * @throws IllegalStateException if the underlying context was closed. * @since 19.0 */ public long asNativePointer() { return impl.asNativePointer(receiver); } /** * Returns true if the value originated form the host language Java. In such a case * the value can be accessed using {@link #asHostObject()}. * * @throws PolyglotException if a guest language error occurred during execution. * @throws IllegalStateException if the underlying context was closed. * @since 19.0 */ public boolean isHostObject() { return impl.isHostObject(receiver); } /** * Returns the original Java host language object. * * @throws UnsupportedOperationException if {@link #isHostObject()} is false. * @throws PolyglotException if a guest language error occurred during execution. * @throws IllegalStateException if the underlying context was closed. * @since 19.0 */ @SuppressWarnings("unchecked") public T asHostObject() { return (T) impl.asHostObject(receiver); } /** * Returns true if this value represents a {@link Proxy}. The proxy instance can be * unboxed using {@link #asProxyObject()}. * * @throws PolyglotException if a guest language error occurred during execution. * @throws IllegalStateException if the underlying context was closed. * @since 19.0 */ public boolean isProxyObject() { return impl.isProxyObject(receiver); } /** * Returns the unboxed instance of the {@link Proxy}. Proxies are not automatically boxed to * {@link #isHostObject() host objects} on host language call boundaries (Java methods). * * @throws UnsupportedOperationException if a value is not a proxy object. * @throws PolyglotException if a guest language error occurred during execution. * @throws IllegalStateException if the underlying context was closed. * @since 19.0 */ @SuppressWarnings("unchecked") public T asProxyObject() { return (T) impl.asProxyObject(receiver); } /** * Maps a polyglot value to a value with a given Java target type. * *

Target type mapping

*

* The following target types are supported and interpreted in the following order: *

    *
  • Custom * {@link HostAccess.Builder#targetTypeMapping(Class, Class, java.util.function.Predicate, Function) * target type mappings} specified in the {@link HostAccess} configuration with precedence * {@link TargetMappingPrecedence#HIGHEST} or {@link TargetMappingPrecedence#HIGH}. These custom * target type mappings may override all the type mappings below. This allows for customization * if one of the below type mappings is not suitable. *
  • {@link Value}.class is always supported and returns this instance. *
  • If the value represents a {@link #isHostObject() host object} then all classes * implemented or extended by the host object can be used as target type. *
  • {@link String}.class is supported if the value is a {@link #isString() * string}. *
  • {@link Character}.class is supported if the value is a {@link #isString() * string} of length one or if a number can be safely be converted to a character. *
  • {@link Number}.class is supported if the value is a {@link #isNumber() * number}. {@link Byte}, {@link Short}, {@link Integer}, {@link Long}, {@link Float} and * {@link Double} are allowed if they fit without conversion. If a conversion is necessary then * a {@link ClassCastException} is thrown. Primitive class literals throw a * {@link NullPointerException} if the value represents {@link #isNull() null}. *
  • {@link Boolean}.class is supported if the value is a {@link #isBoolean() * boolean}. Primitive {@link Boolean boolean.class} literal is also supported. The primitive * class literal throws a {@link NullPointerException} if the value represents {@link #isNull() * null}. *
  • {@link LocalDate}.class is supported if the value is a {@link #isDate() * date}
  • *
  • {@link LocalTime}.class is supported if the value is a {@link #isTime() * time}
  • *
  • {@link LocalDateTime}.class is supported if the value is a {@link #isDate() * date} and {@link #isTime() time}.
  • *
  • {@link Instant}.class is supported if the value is an {@link #isInstant() * instant}.
  • *
  • {@link ZonedDateTime}.class is supported if the value is a {@link #isDate() * date}, {@link #isTime() time} and {@link #isTimeZone() timezone}.
  • *
  • {@link ZoneId}.class is supported if the value is a {@link #isTimeZone() * timezone}.
  • *
  • {@link Duration}.class is supported if the value is a {@link #isDuration() * duration}.
  • *
  • {@link PolyglotException}.class is supported if the value is an * {@link #isException() exception object}.
  • *
  • Any Java type in the type hierarchy of a {@link #isHostObject() host object}. *
  • Custom * {@link HostAccess.Builder#targetTypeMapping(Class, Class, java.util.function.Predicate, Function) * target type mappings} specified in the {@link HostAccess} configuration with precedence * {@link TargetMappingPrecedence#LOW}. *
  • {@link Object}.class is always supported. See section Object mapping rules. *
  • {@link Map}.class is supported if the value has {@link #hasMembers() * members} or {@link #hasArrayElements() array elements}. The returned map can be safely cast * to Map. The key type in such a case is either {@link String} or {@link Long}. * It is recommended to use {@link #as(TypeLiteral) type literals} to specify the expected * collection component types. With type literals the value type can be restricted, for example * to Map. If the raw {@link Map}.class or an Object * component type is used, then the return types of the the list are subject to Object target * type mapping rules recursively. *
  • {@link List}.class is supported if the value has {@link #hasArrayElements() * array elements} and it has an {@link Value#getArraySize() array size} that is smaller or * equal than {@link Integer#MAX_VALUE}. The returned list can be safely cast to * List<Object>. It is recommended to use {@link #as(TypeLiteral) type * literals} to specify the expected component type. With type literals the value type can be * restricted to any supported target type, for example to List<Integer>. If * the raw {@link List}.class or an Object component type is used, then the return * types of the the list are recursively subject to Object target type mapping rules. *
  • Any Java array type of a supported target type. The values of the value will be eagerly * coerced and copied into a new instance of the provided array type. This means that changes in * returned array will not be reflected in the original value. Since conversion to a Java array * might be an expensive operation it is recommended to use the `List` or `Collection` target * type if possible. *
  • Any {@link FunctionalInterface functional} interface if the value can be * {@link #canExecute() executed} or {@link #canInstantiate() instantiated} and the interface * type is {@link HostAccess implementable}. Note that {@link FunctionalInterface} are * implementable by default in with the {@link HostAccess#EXPLICIT explicit} host access policy. * In case a value can be executed and instantiated then the returned implementation of the * interface will be {@link #execute(Object...) executed}. The coercion to the parameter types * of functional interface method is converted using the semantics of {@link #as(Class)}. If a * standard functional interface like {@link Function} is used, it is recommended to use * {@link #as(TypeLiteral) type literals} to specify the expected generic method parameter and * return type. *
  • Any interface if the value {@link #hasMembers() has members} and the interface type is * {@link HostAccess.Implementable implementable}. Each interface method maps to one * {@link #getMember(String) member} of the value. Whenever a method of the interface is * executed a member with the method or field name must exist otherwise an * {@link UnsupportedOperationException} is thrown when the method is executed. If one of the * parameters or the return value cannot be mapped to the target type a * {@link ClassCastException} or a {@link NullPointerException} is thrown. *
  • JVM only: Any abstract class with an accessible default constructor if the value * {@link #hasMembers() has members} and the class is {@link HostAccess.Implementable * implementable}. Each interface method maps to one {@link #getMember(String) member} of the * value. Whenever an abstract method of the class is executed a member with the method or field * name must exist otherwise an {@link UnsupportedOperationException} is thrown when the method * is executed. If one of the parameters or the return value cannot be mapped to the target type * a {@link ClassCastException} or a {@link NullPointerException} is thrown. *
  • Custom * {@link HostAccess.Builder#targetTypeMapping(Class, Class, java.util.function.Predicate, Function) * target type mappings} specified in the {@link HostAccess} configuration with precedence * {@link TargetMappingPrecedence#LOWEST}. *
* A {@link ClassCastException} is thrown for other unsupported target types. *

* JavaScript Usage Examples: * *

     * Context context = Context.newBuilder().allowHostAccess(HostAccess.ALL).build();
     * assert context.eval("js", "undefined").as(Object.class) == null;
     * assert context.eval("js", "'foobar'").as(String.class).equals("foobar");
     * assert context.eval("js", "42").as(Integer.class) == 42;
     * assert context.eval("js", "({foo:'bar'})").as(Map.class).get("foo").equals("bar");
     * assert context.eval("js", "[42]").as(List.class).get(0).equals(42);
     * assert ((Map<String, Object>)context.eval("js", "[{foo:'bar'}]").as(List.class).get(0)).get("foo").equals("bar");
     *
     * @FunctionalInterface interface IntFunction { int foo(int value); }
     * assert context.eval("js", "(function(a){return a})").as(IntFunction.class).foo(42).asInt() == 42;
     *
     * @FunctionalInterface interface StringListFunction { int foo(List<String> value); }
     * assert context.eval("js", "(function(a){return a.length})")
     *               .as(StringListFunction.class).foo(new String[]{"42"}).asInt() == 1;
     *
     * public abstract class AbstractClass { public AbstractClass() {} int foo(int value); }
     * assert context.eval("js", "({foo: function(a){return a}})")
     *               .as(AbstractClass.class).foo(42).asInt() == 42;
     * 
* *

Object target type mapping

*

* Object target mapping is useful to map polyglot values to its closest corresponding standard * JDK type. * * The following rules apply when Object is used as a target type: *

    *
  1. If the value represents {@link #isNull() null} then null is returned. *
  2. If the value is a {@link #isHostObject() host object} then the value is coerced to * {@link #asHostObject() host object value}. *
  3. If the value is a {@link #isString() string} then the value is coerced to {@link String} * or {@link Character}. *
  4. If the value is a {@link #isBoolean() boolean} then the value is coerced to * {@link Boolean}. *
  5. If the value is a {@link #isNumber() number} then the value is coerced to {@link Number}. * The specific sub type of the {@link Number} is not specified. Users need to be prepared for * any Number subclass including {@link BigInteger} or {@link BigDecimal}. It is recommended to * cast to {@link Number} and then convert to a Java primitive like with * {@link Number#longValue()}. *
  6. If the value {@link #hasMembers() has members} then the result value will implement * {@link Map}. If this value {@link #hasMembers() has members} then all members are accessible * using {@link String} keys. The {@link Map#size() size} of the returned {@link Map} is equal * to the count of all members. The returned value may also implement {@link Function} if the * value can be {@link #canExecute() executed} or {@link #canInstantiate() instantiated}. *
  7. If the value has {@link #hasArrayElements() array elements} and it has an * {@link Value#getArraySize() array size} that is smaller or equal than * {@link Integer#MAX_VALUE} then the result value will implement {@link List}. Every array * element of the value maps to one list element. The size of the returned list maps to the * array size of the value. The returned value may also implement {@link Function} if the value * can be {@link #canExecute() executed} or {@link #canInstantiate() instantiated}. *
  8. If the value can be {@link #canExecute() executed} or {@link #canInstantiate() * instantiated} then the result value implements {@link Function Function}. By default the * argument of the function will be used as single argument to the function when executed. If a * value of type {@link Object Object[]} is provided then the function will be executed with * those arguments. The returned function may also implement {@link Map} if the value has * {@link #hasArrayElements() array elements} or {@link #hasMembers() members}. *
  9. If none of the above rules apply then this {@link Value} instance is returned. *
* Returned {@link #isHostObject() host objects}, {@link String}, {@link Number}, * {@link Boolean} and null values have unlimited lifetime. Other values will throw * an {@link IllegalStateException} for any operation if their originating {@link Context * context} was closed. *

* If a {@link Map} element is modified, a {@link List} element is modified or a * {@link Function} argument is provided then these values are interpreted according to the * {@link Context#asValue(Object) host to polyglot value mapping rules}. *

* JavaScript Usage Examples: * *

     * Context context = Context.create();
     * assert context.eval("js", "undefined").as(Object.class) == null;
     * assert context.eval("js", "'foobar'").as(Object.class) instanceof String;
     * assert context.eval("js", "42").as(Object.class) instanceof Number;
     * assert context.eval("js", "[]").as(Object.class) instanceof Map;
     * assert context.eval("js", "{}").as(Object.class) instanceof Map;
     * assert ((Map<Object, Object>) context.eval("js", "[{}]").as(Object.class)).get(0) instanceof Map;
     * assert context.eval("js", "(function(){})").as(Object.class) instanceof Function;
     * 
* *

Object Identity

*

* If polyglot values are mapped as Java primitives such as {@link Boolean}, null, * {@link String}, {@link Character} or {@link Number}, then the identity of the polyglot value * is not preserved. All other results can be converted back to a {@link Value polyglot value} * using {@link Context#asValue(Object)}. * * Mapping Example using JavaScript: This example first creates a new JavaScript object * and maps it to a {@link Map}. Using the {@link Context#asValue(Object)} it is possible to * recreate the {@link Value polyglot value} from the Java map. The JavaScript object identity * is preserved in the process. * *

     * Context context = Context.create();
     * Map<Object, Object> javaMap = context.eval("js", "{}").as(Map.class);
     * Value polyglotValue = context.asValue(javaMap);
     * 
* * @see #as(TypeLiteral) to map to generic type signatures. * @param targetType the target Java type to map * @throws ClassCastException if polyglot value could not be mapped to the target type. * @throws PolyglotException if the conversion triggered a guest language error. * @throws IllegalStateException if the underlying context is already closed. * @throws NullPointerException if the target type is null. * @since 19.0 */ @SuppressWarnings("unchecked") public T as(Class targetType) throws ClassCastException, IllegalStateException, PolyglotException { Objects.requireNonNull(targetType, "targetType"); if (targetType == Value.class) { return (T) this; } return impl.as(receiver, targetType); } /** * Maps a polyglot value to a given Java target type literal. For usage instructions see * {@link TypeLiteral}. *

* Usage example: * *

     * static final TypeLiteral<List<String>> STRING_LIST = new TypeLiteral<List<String>>() {
     * };
     *
     * public static void main(String[] args) {
     *     Context context = Context.create();
     *     List<String> javaList = context.eval("js", "['foo', 'bar', 'bazz']").as(STRING_LIST);
     *     assert javaList.get(0).equals("foo");
     * }
     * 
* * @throws NullPointerException if the target type is null. * @see #as(Class) * @since 19.0 */ public T as(TypeLiteral targetType) { Objects.requireNonNull(targetType, "targetType"); return impl.as(receiver, targetType); } /** * Converts this value to a human readable string. Each language may have special formating * conventions - even primitive values may not follow the traditional Java formating rules. The * format of the returned string is intended to be interpreted by humans not machines and should * therefore not be relied upon by machines. By default this value class name and its * {@link System#identityHashCode(Object) identity hash code} is used as string representation. * * @since 19.0 */ @Override public String toString() { return impl.toString(receiver); } /** * Returns the declared source location of the value. * * @return the {@link SourceSection} or null if unknown * @since 19.0 */ public SourceSection getSourceLocation() { return impl.getSourceLocation(receiver); } /** * Returns true if this object represents a date, else false. If this * value is also a {@link #isTimeZone() timezone} then the date is aware, otherwise it is naive. * * @throws ClassCastException if polyglot value could not be mapped to the target type. * @throws NullPointerException if the target type is null. * @throws PolyglotException if the conversion triggered a guest language error. * @throws IllegalStateException if the underlying context is already closed. * @see #asDate() * @since 19.2.0 */ public boolean isDate() { return impl.isDate(receiver); } /** * Returns this value as date if this object represents a {@link #isDate() date}. The returned * date is either aware if the value has a {@link #isTimeZone() timezone} otherwise it is naive. * * @throws ClassCastException if polyglot value could not be mapped to the target type. * @throws NullPointerException if the target type is null. * @throws PolyglotException if the conversion triggered a guest language error. * @throws IllegalStateException if the underlying context is already closed. * @see #isDate() * @since 19.2.0 */ public LocalDate asDate() { return impl.asDate(receiver); } /** * Returns true if this object represents a time, else false. If the * value is also a {@link #isTimeZone() timezone} then the time is aware, otherwise it is naive. * * @throws IllegalStateException if the underlying context is already closed. * @see #asTime() * @since 19.2.0 */ public boolean isTime() { return impl.isTime(receiver); } /** * Returns this value as time if this object represents a {@link #isTime() time}. The returned * time is either aware if the value has a {@link #isTimeZone() timezone} otherwise it is naive. * * @throws ClassCastException if polyglot value could not be mapped to the target type. * @throws NullPointerException if the target type is null. * @throws PolyglotException if the conversion triggered a guest language error. * @throws IllegalStateException if the underlying context is already closed. * @see #isTime() * @since 19.2.0 */ public LocalTime asTime() { return impl.asTime(receiver); } /** * Returns true if this value represents an instant. If a value is an instant then * it is also a {@link #isDate() date}, {@link #isTime() time} and {@link #isTimeZone() * timezone}. * * This method is short-hand for: * *
     * v.{@linkplain #isDate() isDate}() && v.{@link #isTime() isTime}() && v.{@link #isTimeZone() isTimeZone}()
     * 
* * @throws IllegalStateException if the underlying context is already closed. * @see #isDate() * @see #isTime() * @see #isInstant() * @see #asInstant() * @since 19.2.0 */ public boolean isInstant() { return isDate() && isTime() && isTimeZone(); } /** * Returns this value as instant if this object represents an {@link #isInstant() instant}. If a * value is an instant then it is also a {@link #isDate() date}, {@link #isTime() time} and * {@link #isTimeZone() timezone}. Using this method may be more efficient than reconstructing * the timestamp from the date, time and timezone data. *

* The following assertion always holds if {@link #isInstant()} returns true: * *

     * ZoneId zone = getTimeZone(receiver);
     * LocalDate date = getDate(receiver);
     * LocalTime time = getTime(receiver);
     * assert ZonedDateTime.of(date, time, zone).toInstant().equals(getInstant(receiver));
     * 
* * @throws ClassCastException if polyglot value could not be mapped to the target type. * @throws NullPointerException if the target type is null. * @throws PolyglotException if the conversion triggered a guest language error. * @throws IllegalStateException if the underlying context is already closed. * @see #isDate() * @see #isTime() * @see #isTimeZone() * @since 19.2.0 */ public Instant asInstant() { return impl.asInstant(receiver); } /** * Returns true if this object represents a timezone, else false. The * interpretation of timezone objects may vary: *
    *
  • If {@link #isDate()} and {@link #isTime()} return true, then the returned * date or time information is aware of this timezone. *
  • If {@link #isDate()} and {@link #isTime()} returns false, then it represents * just timezone information. *
* Objects with only date information must not have timezone information attached and objects * with only time information must have either none, or {@link ZoneRules#isFixedOffset() fixed * zone} only. If this rule is violated then an {@link AssertionError} is thrown if assertions * are enabled. *

* If this method is implemented then also {@link #asTimeZone()} must be implemented. * * @throws IllegalStateException if the underlying context is already closed. * @see #asTimeZone() * @see #asInstant() * @since 19.2.0 */ public boolean isTimeZone() { return impl.isTimeZone(receiver); } /** * Returns this value as timestamp if this object represents a {@link #isTimeZone() timezone}. * * @throws ClassCastException if polyglot value could not be mapped to the target type. * @throws PolyglotException if the conversion triggered a guest language error. * @throws IllegalStateException if the underlying context is already closed. * @throws NullPointerException if the target type is null. * @see #isTimeZone() * @since 19.2.0 */ public ZoneId asTimeZone() { return impl.asTimeZone(receiver); } /** * Returns true if this object represents a duration, else false. * * @throws IllegalStateException if the underlying context is already closed. * @see Duration * @see #asDuration() * @since 19.2.0 */ public boolean isDuration() { return impl.isDuration(receiver); } /** * Returns this value as duration if this object represents a {@link #isDuration() duration}. * * @throws ClassCastException if polyglot value could not be mapped to the target type. * @throws PolyglotException if the conversion triggered a guest language error. * @throws IllegalStateException if the underlying context is already closed. * @throws NullPointerException if the target type is null. * @see #isDuration() * @since 19.2.0 */ public Duration asDuration() { return impl.asDuration(receiver); } /** * Returns true if this object represents an exception, else false. * * @throws IllegalStateException if the underlying context is already closed. * @see #throwException() * @since 19.3 */ public boolean isException() { return impl.isException(receiver); } /** * Throws this value if this object represents an {@link #isException() exception}. * * @throws UnsupportedOperationException if the value is not an exception. * @throws IllegalStateException if the underlying context is already closed. * @see #isException() * @since 19.3 */ public RuntimeException throwException() { return impl.throwException(receiver); } /** * Returns the context this value was created with. The returned context may be * null if the value was created using {@link Value#asValue(Object)} and no current * context was {@link Context#enter() entered} at the time. *

* The returned context can not be used to {@link Context#enter() enter} , * {@link Context#leave() leave} or {@link Context#close() close} the context or * {@link Context#getEngine() engine}. Invoking such methods will cause an * {@link IllegalStateException} to be thrown. This ensures that only the * {@link Context#create(String...) creator} of a context is allowed to enter, leave or close a * context and that a context is not closed while it is still active. * * @since 19.3.0 */ public Context getContext() { return impl.getContext(); } /** * Compares the identity of the underlying polyglot objects. This method does not do any * structural comparisons. * * {@inheritDoc} * * @since 20.1 */ @Override public boolean equals(Object obj) { if (!(obj instanceof Value)) { return false; } return impl.equalsImpl(receiver, ((Value) obj).receiver); } /** * Returns the identity hash code of the underlying object. This method does not compute the * hash code depending on the contents of the value. * * {@inheritDoc} * * @since 20.1 */ @Override public int hashCode() { return impl.hashCodeImpl(receiver); } /** * Converts a Java host value to a polyglot value. Returns a value for any host or guest value. * If there is a context available use {@link Context#asValue(Object)} for efficiency instead. * The value is bound the {@link Context#getCurrent() current} context when created. If there is * no context available when the value was constructed then Values constructed with this method * may return null for {@link #getContext()}. * * @param o the object to convert * @throws IllegalStateException if no context is currently entered. * @see Context#asValue(Object) Conversion rules. * @since 19.0 */ public static Value asValue(Object o) { if (o instanceof Value) { return (Value) o; } return Engine.getImpl().asValue(o); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy