diff --git a/README.rst b/README.rst
index a9897e777..3384d5424 100644
--- a/README.rst
+++ b/README.rst
@@ -52,14 +52,14 @@ Maven
com.caoccao.javet
javet
- 0.9.9
+ 0.9.10
com.caoccao.javet
javet-macos
- 0.9.9
+ 0.9.10
Gradle Kotlin DSL
@@ -67,16 +67,16 @@ Gradle Kotlin DSL
.. code-block:: kotlin
- implementation("com.caoccao.javet:javet:0.9.9") // Linux or Windows
- implementation("com.caoccao.javet:javet-macos:0.9.9") // Mac OS (x86_64 Only)
+ implementation("com.caoccao.javet:javet:0.9.10") // Linux or Windows
+ implementation("com.caoccao.javet:javet-macos:0.9.10") // Mac OS (x86_64 Only)
Gradle Groovy DSL
^^^^^^^^^^^^^^^^^
.. code-block:: groovy
- implementation 'com.caoccao.javet:javet:0.9.9' // Linux or Windows
- implementation 'com.caoccao.javet:javet-macos:0.9.9' // Mac OS (x86_64 Only)
+ implementation 'com.caoccao.javet:javet:0.9.10' // Linux or Windows
+ implementation 'com.caoccao.javet:javet-macos:0.9.10' // Mac OS (x86_64 Only)
Hello Javet
-----------
diff --git a/build.gradle.kts b/build.gradle.kts
index 11c9689f5..60e421b08 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -25,7 +25,7 @@ repositories {
}
group = "com.caoccao.javet"
-version = "0.9.9"
+version = "0.9.10"
repositories {
mavenCentral()
diff --git a/cpp/build-linux.sh b/cpp/build-linux.sh
index e2358c1e9..ef2cc8062 100755
--- a/cpp/build-linux.sh
+++ b/cpp/build-linux.sh
@@ -2,7 +2,7 @@
# Usage for V8: sh build-linux.sh -DV8_DIR=${HOME}/v8
# Usage for Node: sh build-linux.sh -DNODE_DIR=${HOME}/node
-JAVET_VERSION=0.9.9
+JAVET_VERSION=0.9.10
rm -rf build
mkdir build
cd build
diff --git a/cpp/build-macos.sh b/cpp/build-macos.sh
index 107565ac5..bf7141ad4 100755
--- a/cpp/build-macos.sh
+++ b/cpp/build-macos.sh
@@ -2,7 +2,7 @@
# Usage for V8: sh build-macos.sh -DV8_DIR=${HOME}/v8
# Usage for Node: sh build-macos.sh -DNODE_DIR=${HOME}/node
-JAVET_VERSION=0.9.9
+JAVET_VERSION=0.9.10
rm -rf build
mkdir build
cd build
diff --git a/cpp/build-windows.cmd b/cpp/build-windows.cmd
index 6bf45d659..81bda13a0 100644
--- a/cpp/build-windows.cmd
+++ b/cpp/build-windows.cmd
@@ -1,7 +1,7 @@
@echo off
REM Usage for V8: build -DV8_DIR=C:\v8
REM Usage for Node: build -DNODE_DIR=C:\node
-SET JAVET_VERSION=0.9.9
+SET JAVET_VERSION=0.9.10
rd /s/q build
mkdir build
cd build
diff --git a/cpp/jni/javet_resource_node.rc b/cpp/jni/javet_resource_node.rc
index ce4c6a88b..049116169 100644
--- a/cpp/jni/javet_resource_node.rc
+++ b/cpp/jni/javet_resource_node.rc
@@ -61,8 +61,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 0,9,9,0
- PRODUCTVERSION 0,9,9,0
+ FILEVERSION 0,9,10,0
+ PRODUCTVERSION 0,9,10,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -79,12 +79,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "caoccao.com"
VALUE "FileDescription", "caoccao.com"
- VALUE "FileVersion", "0.9.9.0"
- VALUE "InternalName", "libjavet-node-windows-x86_64.v.0.9.9.dll"
+ VALUE "FileVersion", "0.9.10.0"
+ VALUE "InternalName", "libjavet-node-windows-x86_64.v.0.9.10.dll"
VALUE "LegalCopyright", "Copyright (C) 2021"
- VALUE "OriginalFilename", "libjavet-node-windows-x86_64.v.0.9.9.dll"
+ VALUE "OriginalFilename", "libjavet-node-windows-x86_64.v.0.9.10.dll"
VALUE "ProductName", "Javet Windows"
- VALUE "ProductVersion", "0.9.9.0"
+ VALUE "ProductVersion", "0.9.10.0"
END
END
BLOCK "VarFileInfo"
diff --git a/cpp/jni/javet_resource_v8.rc b/cpp/jni/javet_resource_v8.rc
index bf9ac3a62..365be50b0 100644
--- a/cpp/jni/javet_resource_v8.rc
+++ b/cpp/jni/javet_resource_v8.rc
@@ -61,8 +61,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 0,9,9,0
- PRODUCTVERSION 0,9,9,0
+ FILEVERSION 0,9,10,0
+ PRODUCTVERSION 0,9,10,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -79,12 +79,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "caoccao.com"
VALUE "FileDescription", "caoccao.com"
- VALUE "FileVersion", "0.9.9.0"
- VALUE "InternalName", "libjavet-v8-windows-x86_64.v.0.9.9.dll"
+ VALUE "FileVersion", "0.9.10.0"
+ VALUE "InternalName", "libjavet-v8-windows-x86_64.v.0.9.10.dll"
VALUE "LegalCopyright", "Copyright (C) 2021"
- VALUE "OriginalFilename", "libjavet-v8-windows-x86_64.v.0.9.9.dll"
+ VALUE "OriginalFilename", "libjavet-v8-windows-x86_64.v.0.9.10.dll"
VALUE "ProductName", "Javet Windows"
- VALUE "ProductVersion", "0.9.9.0"
+ VALUE "ProductVersion", "0.9.10.0"
END
END
BLOCK "VarFileInfo"
diff --git a/docker/windows-x86_64/base.Dockerfile b/docker/windows-x86_64/base.Dockerfile
index e8468877c..304b06009 100644
--- a/docker/windows-x86_64/base.Dockerfile
+++ b/docker/windows-x86_64/base.Dockerfile
@@ -13,21 +13,111 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# Usage: docker build -t sjtucaocao/javet-windows:0.9.9 -f docker/windows-x86_64/base.Dockerfile .
-# Note: This is experimental and it doesn't work as expected yet.
+# Preparation:
+# Visual Studio installer validates free disk space and refuses to work with the docker default one.
+# Please follow the steps to set free disk space to 120GB.
+# 1. Update daemon.json
+# "storage-opts": [
+# "dm.basesize=120GB",
+# "size=120GB"
+# ]
+# 2. Restart WSL2
+# 3. Restart docker
-# https://hub.docker.com/_/microsoft-dotnet-framework-sdk/
-FROM mcr.microsoft.com/dotnet/framework/sdk:4.8-windowsservercore-20H2
+# Usage: docker build -t sjtucaocao/javet-windows:0.9.10 -m 4G -f docker/windows-x86_64/base.Dockerfile .
+
+# https://hub.docker.com/_/microsoft-windows
+FROM mcr.microsoft.com/windows:20H2-amd64
SHELL ["cmd", "/S", "/C"]
-RUN curl -SL --output vs_buildtools.exe https://aka.ms/vs/16/release/vs_buildtools.exe
-RUN start /w vs_buildtools.exe --quiet --wait --norestart --nocache modify \
- --installPath "%ProgramFiles(x86)%\Microsoft Visual Studio\2019\BuildTools" \
+WORKDIR /
+
+# Install Python 3
+RUN curl -SL --output python-3.9.6-amd64.exe https://www.python.org/ftp/python/3.9.6/python-3.9.6-amd64.exe
+RUN start /w python-3.9.6-amd64.exe /quiet InstallAllUsers=1 PrependPath=0
+RUN del /q python-3.9.6-amd64.exe
+
+# Install Python 2
+RUN curl -SL --output python-2.7.18.msi https://www.python.org/ftp/python/2.7.18/python-2.7.18.msi
+RUN start /w msiexec.exe /i python-2.7.18.msi ALLUSERS=1 ADDLOCAL=ALL /qn
+RUN del /q python-2.7.18.msi
+
+# Install Git for Windows
+# https://github.com/git-for-windows/git/wiki/Silent-or-Unattended-Installation
+RUN curl -SL --output Git-2.32.0.2-64-bit.exe https://github.com/git-for-windows/git/releases/download/v2.32.0.windows.2/Git-2.32.0.2-64-bit.exe
+RUN start /w Git-2.32.0.2-64-bit.exe /VERYSILENT /NORESTART /NOCANCEL /SP- /CLOSEAPPLICATIONS /RESTARTAPPLICATIONS /COMPONENTS="icons,ext\reg\shellhere,assoc,assoc_sh"
+RUN del /q Git-2.32.0.2-64-bit.exe
+
+# Prepare V8
+RUN mkdir google
+WORKDIR /google
+RUN git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
+WORKDIR /google/depot_tools
+RUN git checkout remotes/origin/master
+RUN setx /M PATH "C:\google\depot_tools;%PATH%"
+ENV DEPOT_TOOLS_WIN_TOOLCHAIN=0
+WORKDIR /google
+RUN fetch v8
+WORKDIR /google/v8
+RUN git checkout 9.2.230.21
+WORKDIR /google
+RUN gclient sync
+RUN echo V8 preparation is completed.
+
+# Install Visual Studio 2019 Community
+# https://docs.microsoft.com/en-us/visualstudio/install/workload-component-id-vs-community?view=vs-2019
+# https://docs.microsoft.com/en-us/visualstudio/install/create-an-offline-installation-of-visual-studio?view=vs-2019
+WORKDIR /
+RUN curl -SL --output vs_community.exe https://aka.ms/vs/16/release/vs_community.exe
+RUN echo Installing Visual Studio 2019 Community
+RUN start /w vs_community.exe \
+ --wait --quiet --norestart --nocache --includeRecommended --includeOptional \
+ --installPath "%ProgramFiles(x86)%\Microsoft Visual Studio\2019\Community" \
+ --add Microsoft.VisualStudio.Workload.NativeDesktop \
+ --add Microsoft.VisualStudio.Workload.NativeCrossPlat \
--remove Microsoft.VisualStudio.Component.Windows10SDK.10240 \
--remove Microsoft.VisualStudio.Component.Windows10SDK.10586 \
- --remove Microsoft.VisualStudio.Component.Windows81SDK \
|| IF "%ERRORLEVEL%"=="3010" EXIT 0
-RUN del /q vs_buildtools.exe
-ENTRYPOINT ["C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools\\Common7\\Tools\\VsDevCmd.bat", "&&", "powershell.exe", "-NoLogo", "-ExecutionPolicy", "Bypass"]
+# Install Windows SDK 10.0.19041.x
+RUN curl -SL --output winsdksetup.exe https://go.microsoft.com/fwlink/p/?linkid=2120843
+RUN start /w winsdksetup.exe /norestart /quiet /ceip off /features +
+RUN del /q vs_community.exe
+RUN del /q winsdksetup.exe
+
+# Build V8
+WORKDIR /google/v8
+RUN setx /M PATH "C:\Python27;C:\Python27\Scripts;%PATH%"
+RUN python tools/dev/v8gen.py x64.release -vv -- v8_monolithic=true v8_use_external_startup_data=false is_component_build=false v8_enable_i18n_support=false v8_enable_pointer_compression=false v8_static_library=true symbol_level=0 use_custom_libcxx=false
+RUN ninja -C out.gn/x64.release v8_monolith || EXIT 0
+COPY ./scripts/python/patch_v8_build.py .
+RUN ["C:\\Program Files\\Python39\\python.exe", "C:\\google\\v8\\patch_v8_build.py", "-p", "C:\\google\\v8\\"]
+RUN ninja -C out.gn/x64.release v8_monolith
+RUN del patch_v8_build.py
+RUN echo V8 build is completed.
+
+# Prepare Node.js
+WORKDIR /
+RUN powershell -ExecutionPolicy Bypass -c "iex(New-Object Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1')"
+RUN choco install -y nasm
+RUN git clone https://github.com/nodejs/node.git
+WORKDIR /node
+RUN git checkout v14.17.4
+RUN echo Node.js preparation is completed.
+
+# Build Node.js
+RUN vcbuild.bat static without-intl
+RUN echo Node.js build is completed.
+
+# Prepare Javet Build Environment
+RUN choco install -y openjdk8
+RUN setx /M PATH "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin;%PATH%"
+RUN setx /M PATH "C:\Program Files\Git\usr\bin;%PATH%"
+
+# Shrink
+WORKDIR /
+RUN rd /s /q "C:\Users\ContainerAdministrator\AppData\Local\Temp"
+
+# Completed
+RUN echo Javet build base image is completed.
diff --git a/docker/windows-x86_64/build.Dockerfile b/docker/windows-x86_64/build.Dockerfile
new file mode 100644
index 000000000..3a5f4eb70
--- /dev/null
+++ b/docker/windows-x86_64/build.Dockerfile
@@ -0,0 +1,43 @@
+# Copyright (c) 2021 caoccao.com Sam Cao
+# All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Usage: docker build -t javet:local -f docker/windows-x86_64/build.Dockerfile .
+
+FROM sjtucaocao/javet-windows:0.9.10
+
+SHELL ["cmd", "/S", "/C"]
+WORKDIR /
+
+# Copy Javet
+RUN mkdir Javet
+WORKDIR /Javet
+COPY . .
+
+# Build JNI
+WORKDIR /Javet/cpp
+RUN build-windows.cmd -DV8_DIR="C:\google\v8"
+RUN build-windows.cmd -DNODE_DIR="C:\node"
+
+# Build Jar
+WORKDIR /Javet
+RUN touch src/main/resources/libjavet-v8*
+RUN gradlew build test --rerun-tasks
+RUN touch src/main/resources/libjavet-node*
+RUN gradlew test --rerun-tasks
+
+VOLUME C:\\output
+
+# Completed
+RUN echo Javet build is completed.
diff --git a/docs/development/build.rst b/docs/development/build.rst
index 20229c84a..5d47f1c0d 100644
--- a/docs/development/build.rst
+++ b/docs/development/build.rst
@@ -10,7 +10,7 @@ It's quite hard for developers to build Javet successfully for various reasons.
Here are 3 ways of building Javet.
-1. `Build Javet with Docker `_ (Linux)
+1. `Build Javet with Docker `_ (Linux and Windows)
2. `Build Javet with Pre-built Binaries `_ (Linux, Mac OS and Windows)
3. `Build Javet from Scratch `_ (Linux, Mac OS and Windows)
diff --git a/docs/development/build_javet_with_docker.rst b/docs/development/build_javet_with_docker.rst
index f17221f03..138030a6a 100644
--- a/docs/development/build_javet_with_docker.rst
+++ b/docs/development/build_javet_with_docker.rst
@@ -2,9 +2,9 @@
Build Javet with Docker
=======================
-For now, the Docker build only supports building Javet on Linux. As Docker supports Linux and Windows with WSL2, Javet for Linux can also be built on Windows.
+The Docker build supports building Javet for Linux and Windows. As Docker supports Linux and Windows with WSL2, Javet for Linux can also be built on Windows.
-Regarding Docker build for Mac OS or Windows, contributors are welcome if you are interested. Or, you will have to wait for a long while.
+Regarding Docker build for Mac OS, contributors are welcome if you are interested. Or, you will have to wait for a long while.
Build Environment
=================
@@ -27,10 +27,10 @@ Windows Environment
Docker Hub and Github
---------------------
-Please make sure the network connection to the Docker Hub and Github is up and running. The Docker repository of the Javet images are available at https://hub.docker.com/repository/docker/sjtucaocao/javet.
+Please make sure the network connection to the Docker Hub and Github is up and running. The Docker repository of the Javet images are available at https://hub.docker.com/repository/docker/sjtucaocao.
-Build Javet on Linux
-====================
+Build Javet for Linux on Linux or Windows
+=========================================
1. Clone Javet.
2. Navigate to the root directory of the Javet repository.
@@ -39,4 +39,28 @@ Build Javet on Linux
* Docker will pull the corresponding image (~10GB) from Docker Hub.
* The actual build takes few minutes including pulling dependent libraries from Maven Central, building and testing.
+Build Javet for Windows on Windows
+==================================
+
+1. Update daemon.json
+
+.. code-block:: json
+
+ "storage-opts": [
+ "dm.basesize=120GB",
+ "size=120GB"
+ ]
+
+2. Restart WSL2
+3. Restart docker
+4. Clone Javet.
+5. Navigate to the root directory of the Javet repository.
+6. Execute ``docker build -t sjtucaocao/javet-windows:x.x.x -m 4G -f docker/windows-x86_64/base.Dockerfile .`` (Be careful, please include the last ``.``).
+7. Execute ``docker build -f docker/windows-x86_64/build.Dockerfile .`` (Be careful, please include the last ``.``).
+
+Note:
+
+* The base image is so large (60+GB) that it's not efficient to push the base image to docker hub. Of course, without the base image at docker hub, it's not wise to enable the github workflow for Windows build.
+* Building the base image takes many hours and may experience intermittent errors.
+
[`Home <../../README.rst>`_] [`Development `_]
diff --git a/docs/development/build_javet_with_pre_built_binaries.rst b/docs/development/build_javet_with_pre_built_binaries.rst
index 294741c03..3debd6f57 100644
--- a/docs/development/build_javet_with_pre_built_binaries.rst
+++ b/docs/development/build_javet_with_pre_built_binaries.rst
@@ -38,6 +38,8 @@ Download Pre-built Node.js and V8
I have prepared pre-built Linux and Windows version of Node.js ``v14.17.4`` and V8 ``v9.2.230.21``. Please download the zipped headers and binaries from this `drive `_ and unzip them to local folders respectively.
+Note: As the docker builds are available, I'll stop publishing pre-built binaries. If you really need them, please contact the maintainer wisely.
+
Build Javet JNI Library
=======================
diff --git a/docs/development/index.rst b/docs/development/index.rst
index 3e5e75144..8da39dc1c 100644
--- a/docs/development/index.rst
+++ b/docs/development/index.rst
@@ -5,7 +5,7 @@ Development
* `Development Tools `_
* `Build `_
- * `Build Javet with Docker `_ (Linux)
+ * `Build Javet with Docker `_ (Linux and Windows)
* `Build Javet with Pre-built Binaries `_ (Linux, Mac OS and Windows)
* `Build Javet from Scratch `_ (Linux, Mac OS and Windows)
diff --git a/docs/reference/error_codes.rst b/docs/reference/error_codes.rst
index cc4f71a25..e31300b2e 100644
--- a/docs/reference/error_codes.rst
+++ b/docs/reference/error_codes.rst
@@ -40,6 +40,8 @@ Code Type Name Format
501 Converter ConverterFailure Failed to convert values with error message ${message}
502 Converter ConverterCircularStructure Circular structure is detected with max depth ${maxDepth} reached
601 Module ModuleNameEmpty Module name is empty
+602 Module ModuleNotFound Module ${moduleName} is not found
+603 Module ModulePermissionDenied Denied access to module ${moduleName}
701 Lock LockAcquisitionFailure Failed to acquire the lock
702 Lock LockReleaseFailure Failed to release the lock
703 Lock LockConflictThreadIdMismatch Runtime lock conflict is detected with locked thread ID ${lockedThreadID} and current thread ID ${currentThreadID}
diff --git a/docs/release_notes.rst b/docs/release_notes.rst
index 34de260ce..6c7b8c977 100644
--- a/docs/release_notes.rst
+++ b/docs/release_notes.rst
@@ -2,6 +2,16 @@
Release Notes
=============
+0.9.10
+------
+
+* Added ``JavetVirtualObject``
+* Updated ``JavetUniversalProxyHandler`` to allow passing ``V8Value``
+* Updated ``JavetUniversalProxyHandler`` to allow passing ``V8ValueFunction`` as anonymous function
+* Updated ``JavetUniversalProxyHandler`` to allow passing ``V8ValueObject`` as anonymous object
+* Added ``isClosed()`` to ``IJavetClosable``
+* Added error code 602 and 603
+
0.9.9
-----
diff --git a/docs/tutorial/installation.rst b/docs/tutorial/installation.rst
index 33b873fe6..cd4de859d 100644
--- a/docs/tutorial/installation.rst
+++ b/docs/tutorial/installation.rst
@@ -14,14 +14,14 @@ Maven
com.caoccao.javet
javet
- 0.9.9
+ 0.9.10
-
+
com.caoccao.javet
javet-macos
- 0.9.9
+ 0.9.10
Gradle Kotlin DSL
@@ -29,15 +29,16 @@ Gradle Kotlin DSL
.. code-block:: kotlin
- implementation("com.caoccao.javet:javet:0.9.9") // Linux or Windows
- implementation("com.caoccao.javet:javet-macos:0.9.9") // Mac OS
+ implementation("com.caoccao.javet:javet:0.9.10") // Linux or Windows
+ implementation("com.caoccao.javet:javet-macos:0.9.10") // Mac OS (x86_64 Only)
Gradle Groovy DSL
-----------------
.. code-block:: groovy
- implementation 'com.caoccao.javet:javet:0.9.9'
+ implementation 'com.caoccao.javet:javet:0.9.10' // Linux or Windows
+ implementation 'com.caoccao.javet:javet-macos:0.9.10' // Mac OS (x86_64 Only)
OS Compatibility
================
@@ -52,7 +53,7 @@ Ubuntu 20.04 Yes
Ubuntu 18.04 Yes (`Private Build `_)
Ubuntu 16.04 Yes (`Private Build `_)
Other Linux Distributions Not Tested
-MacOS x86_64 Experimental (`Private Build `_)
+MacOS x86_64 Yes
MacOS arm64 No (`Can Javet Support Mac? <../faq/can_javet_support_mac.rst>`_)
=========================== =======================================================================================================================
diff --git a/docs/tutorial/object_converter.rst b/docs/tutorial/object_converter.rst
index 605afd13e..2c413a4a6 100644
--- a/docs/tutorial/object_converter.rst
+++ b/docs/tutorial/object_converter.rst
@@ -282,6 +282,135 @@ Sometimes an interface or annotation class can be injected for enabling Java ref
v8Runtime.getGlobalObject().delete("IJavetClosable");
v8Runtime.lowMemoryNotification();
+Dynamic: Anonymous Function
+---------------------------
+
+This feature is quite special as it allows implementing Java interfaces in JavaScript via anonymous functions, also known as lambda expressions.
+
+1. Define a simple interface ``IStringJoiner`` for joining two strings.
+
+.. code-block:: java
+
+ interface IStringJoiner extends AutoCloseable {
+ String join(String a, String b);
+ }
+
+2. Define a simple class ``StringJoiner`` which holds the interface ``IStringJoiner``.
+
+.. code-block:: java
+
+ public class StringJoiner implements AutoCloseable {
+ private IStringJoiner joiner;
+
+ public StringJoiner() {
+ joiner = null;
+ }
+
+ @Override
+ public void close() throws Exception {
+ if (joiner != null) {
+ joiner.close();
+ joiner = null;
+ }
+ }
+
+ public IStringJoiner getJoiner() {
+ return joiner;
+ }
+
+ public void setJoiner(IStringJoiner joiner) {
+ this.joiner = joiner;
+ }
+ }
+
+3. Inject the implementation from JavaScript.
+
+.. code-block:: java
+
+ try (StringJoiner stringJoiner = new StringJoiner()) {
+ v8Runtime.getGlobalObject().set("stringJoiner", stringJoiner);
+ v8Runtime.getExecutor("stringJoiner.setJoiner((a, b) => a + ',' + b);").executeVoid();
+ IStringJoiner joiner = stringJoiner.getJoiner();
+ assertEquals("a,b", joiner.join("a", "b"));
+ assertEquals("a,b,c", joiner.join(joiner.join("a", "b"), "c"));
+ v8Runtime.getGlobalObject().delete("stringJoiner");
+ }
+ v8Runtime.lowMemoryNotification();
+
+VoilĂ ! It works.
+
+Note: The JavaScript implementation is backed up by ``V8ValueFunction`` which is an orphan object. After its internal ``V8Runtime`` is closed, it will no longer callable. It's recommended to have the interface implement ``AutoClosable`` as the sample shows so that the orphan ``V8ValueFunction`` can be recycled explicitly. If you don't own the interface, Javet will force the recycle of the orphan ``V8ValueFunction`` when the ``V8Runtime`` is being closed. Be careful, if you keep the application running for long while without recycling them in time, ``OutOfMemoryError`` may occur.
+
+Dynamic: Anonymous Object
+-------------------------
+
+This feature is similar to the dynamic anonymous function, but is an enhanced version because it allows implementing all methods exposed by the Java interface.
+
+1. Define a simple interface ``IStringUtils`` for joining two strings.
+
+.. code-block:: java
+
+ interface IStringUtils extends AutoCloseable {
+ String hello();
+ String join(String separator, String... strings);
+ List split(String separator, String string);
+ }
+
+2. Define a simple class ``StringUtils`` which holds the interface ``IStringUtils``.
+
+.. code-block:: java
+
+ public class StringUtils implements AutoCloseable {
+ private IStringUtils utils;
+
+ public StringUtils() {
+ utils = null;
+ }
+
+ @Override
+ public void close() throws Exception {
+ if (utils != null) {
+ utils.close();
+ utils = null;
+ }
+ }
+
+ public IStringUtils getUtils() {
+ return utils;
+ }
+
+ public void setUtils(IStringUtils utils) {
+ this.utils = utils;
+ }
+ }
+
+3. Inject the implementation from JavaScript.
+
+.. code-block:: java
+
+ try (StringUtils stringUtils = new StringUtils()) {
+ v8Runtime.getGlobalObject().set("stringUtils", stringUtils);
+ v8Runtime.getExecutor(
+ "stringUtils.setUtils({\n" +
+ " hello: () => 'hello',\n" +
+ " join: (separator, ...strings) => [...strings].join(separator),\n" +
+ " split: (separator, str) => str.split(separator),\n" +
+ "});"
+ ).executeVoid();
+ IStringUtils utils = stringUtils.getUtils();
+ assertEquals("hello", utils.hello());
+ assertEquals("a,b,c", utils.join(",", "a", "b", "c"));
+ assertArrayEquals(
+ new String[]{"a", "b", "c"},
+ utils.split(",", "a,b,c").toArray(new String[0]));
+ v8Runtime.getGlobalObject().delete("stringUtils");
+ }
+ v8Runtime.lowMemoryNotification();
+
+VoilĂ aussi! It works again.
+
+Note: The JavaScript implementation is backed up by ``V8ValueObject`` which is an orphan object. After its internal ``V8Runtime`` is closed, it will no longer callable. It's recommended to have the interface implement ``AutoClosable`` as the sample shows so that the orphan ``V8ValueObject`` can be recycled explicitly. If you don't own the interface, Javet will force the recycle of the orphan ``V8ValueObject`` when the ``V8Runtime`` is being closed. Be careful, if you keep the application running for long while without recycling them in time, ``OutOfMemoryError`` may occur.
+
Features
--------
@@ -289,6 +418,7 @@ Features
* Getters and setters (``get``, ``is``, ``set`` and ``put``) are smartly handled.
* Overloaded methods and varargs methods are identified well.
* Primitive types, Set, Map, List, Array are not handled. Map is special because it can be enabled.
+* Java interfaces can be implemented by anonymous functions in JavaScript.
How does JavetProxyConverter Work?
----------------------------------
diff --git a/pom.xml b/pom.xml
index e42dab25d..d6e3944f4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
com.caoccao.javet
javet
- 0.9.9
+ 0.9.10
javet
Javet is Java + V8 (JAVa + V + EighT). It is a way of embedding V8 in Java.
https://github.com/caoccao/Javet
@@ -28,7 +28,7 @@
scm:git:git://github.com/caoccao/Javet.git
scm:git:git@github.com:caoccao/caoccao.git
https://github.com/caoccao/Javet
- javet-0.9.9
+ javet-0.9.10
diff --git a/scripts/node/javet-rebuild/rebuild.cmd b/scripts/node/javet-rebuild/rebuild.cmd
index afdefeb73..76a650344 100644
--- a/scripts/node/javet-rebuild/rebuild.cmd
+++ b/scripts/node/javet-rebuild/rebuild.cmd
@@ -1,5 +1,5 @@
@echo off
-SET NODE_LIB_FILE="..\..\..\..\..\..\build\libs\libjavet-node-windows-x86_64.v.0.9.9.lib"
+SET NODE_LIB_FILE="..\..\..\..\..\..\build\libs\libjavet-node-windows-x86_64.v.0.9.10.lib"
cd %NODE_MODULE_ROOT%
call node-gyp clean
call node-gyp configure --module_name=%NODE_MODULE_NAME% --module_path=%NODE_MODULE_PATH% --node_lib_file=%NODE_LIB_FILE%
diff --git a/scripts/node/javet-rebuild/rebuild.sh b/scripts/node/javet-rebuild/rebuild.sh
index 440a95093..9d9e9d0b9 100755
--- a/scripts/node/javet-rebuild/rebuild.sh
+++ b/scripts/node/javet-rebuild/rebuild.sh
@@ -1 +1 @@
-patchelf --add-needed libjavet-node-linux-x86_64.v.0.9.9.so ${NODE_MODULE_FILE}
+patchelf --add-needed libjavet-node-linux-x86_64.v.0.9.10.so ${NODE_MODULE_FILE}
diff --git a/scripts/python/change_javet_version.py b/scripts/python/change_javet_version.py
index 9d30443ab..5501d7c68 100644
--- a/scripts/python/change_javet_version.py
+++ b/scripts/python/change_javet_version.py
@@ -35,8 +35,7 @@ def update(self):
self._update(
'README.rst', '\n',
re.compile(r'^ (?P\d+\.\d+\.\d+)$'),
- re.compile(r'javet:(?P\d+\.\d+\.\d+)"'),
- re.compile(r'javet:(?P\d+\.\d+\.\d+)\''),
+ re.compile(r'javet[\-\w]*:(?P\d+\.\d+\.\d+)["\']{1}'),
re.compile(r'version: \'(?P\d+\.\d+\.\d+)\''))
self._update(
'build.gradle.kts', '\n',
@@ -44,18 +43,20 @@ def update(self):
self._update(
'docs/tutorial/installation.rst', '\n',
re.compile(r'^ (?P\d+\.\d+\.\d+)$'),
- re.compile(r'javet:(?P\d+\.\d+\.\d+)"'),
- re.compile(r'javet:(?P\d+\.\d+\.\d+)\''),
+ re.compile(r'javet[\-\w]*:(?P\d+\.\d+\.\d+)["\']{1}'),
re.compile(r'version: \'(?P\d+\.\d+\.\d+)\''))
self._update(
'pom.xml', '\n',
re.compile(r'^ (?P\d+\.\d+\.\d+)$'),
re.compile(r'^ javet-(?P\d+\.\d+\.\d+)$'))
self._update(
- 'cpp/build.cmd', '\r\n',
+ 'cpp/build-linux.sh', '\n',
re.compile(r'JAVET_VERSION=(?P\d+\.\d+\.\d+)$'))
self._update(
- 'cpp/build.sh', '\n',
+ 'cpp/build-macos.sh', '\n',
+ re.compile(r'JAVET_VERSION=(?P\d+\.\d+\.\d+)$'))
+ self._update(
+ 'cpp/build-windows.cmd', '\r\n',
re.compile(r'JAVET_VERSION=(?P\d+\.\d+\.\d+)$'))
self._update(
'src/main/java/com/caoccao/javet/interop/JavetLibLoader.java', '\n',
@@ -109,7 +110,7 @@ def _update(self, relative_file_path: str, line_separator: str, *patterns: list)
logging.info(' Updated.')
def main():
- change_javet_version = ChangeJavetVersion('0.9.9')
+ change_javet_version = ChangeJavetVersion('0.9.10')
change_javet_version.update()
return 0
diff --git a/src/main/java/com/caoccao/javet/exceptions/JavetError.java b/src/main/java/com/caoccao/javet/exceptions/JavetError.java
index fac7e2c7f..7ce51b189 100644
--- a/src/main/java/com/caoccao/javet/exceptions/JavetError.java
+++ b/src/main/java/com/caoccao/javet/exceptions/JavetError.java
@@ -91,6 +91,10 @@ public class JavetError {
public static final JavetError ModuleNameEmpty = new JavetError(
601, JavetErrorType.Module, "Module name is empty");
+ public static final JavetError ModuleNotFound = new JavetError(
+ 602, JavetErrorType.Module, "Module ${moduleName} is not found");
+ public static final JavetError ModulePermissionDenied = new JavetError(
+ 603, JavetErrorType.Module, "Denied access to module ${moduleName}");
public static final JavetError LockAcquisitionFailure = new JavetError(
701, JavetErrorType.Lock, "Failed to acquire the lock");
diff --git a/src/main/java/com/caoccao/javet/interfaces/IJavetClosable.java b/src/main/java/com/caoccao/javet/interfaces/IJavetClosable.java
index 75457bb2b..f4dc0e2aa 100644
--- a/src/main/java/com/caoccao/javet/interfaces/IJavetClosable.java
+++ b/src/main/java/com/caoccao/javet/interfaces/IJavetClosable.java
@@ -26,4 +26,12 @@
*/
public interface IJavetClosable extends AutoCloseable {
void close() throws JavetException;
+
+ /**
+ * Is closed.
+ *
+ * @return the boolean
+ * @since 0.9.10
+ */
+ boolean isClosed();
}
diff --git a/src/main/java/com/caoccao/javet/interop/JavetLibLoader.java b/src/main/java/com/caoccao/javet/interop/JavetLibLoader.java
index e7694a9c2..75b1f9293 100644
--- a/src/main/java/com/caoccao/javet/interop/JavetLibLoader.java
+++ b/src/main/java/com/caoccao/javet/interop/JavetLibLoader.java
@@ -33,7 +33,7 @@
import java.util.Objects;
public final class JavetLibLoader {
- static final String LIB_VERSION = "0.9.9";
+ static final String LIB_VERSION = "0.9.10";
private static final int BUFFER_LENGTH = 4096;
private static final String CHMOD = "chmod";
private static final String LIB_FILE_EXTENSION_LINUX = "so";
diff --git a/src/main/java/com/caoccao/javet/interop/V8Locker.java b/src/main/java/com/caoccao/javet/interop/V8Locker.java
index 31ea6f1bf..755b5317f 100644
--- a/src/main/java/com/caoccao/javet/interop/V8Locker.java
+++ b/src/main/java/com/caoccao/javet/interop/V8Locker.java
@@ -27,18 +27,21 @@
/**
* The type V8 locker.
* It's designed for performance sensitive scenarios.
+ * @since 0.7.3
*/
public final class V8Locker implements IJavetClosable {
private final long threadId;
private final IV8Native v8Native;
private final V8Runtime v8Runtime;
+ private boolean locked;
/**
* Instantiates a new V8 locker.
*
* @param v8Runtime the V8 runtime
- * @param v8Native the v 8 native
+ * @param v8Native the V8 native
* @throws JavetException the javet exception
+ * @since 0.7.3
*/
V8Locker(V8Runtime v8Runtime, IV8Native v8Native) throws JavetException {
Objects.requireNonNull(v8Runtime);
@@ -48,6 +51,7 @@ public final class V8Locker implements IJavetClosable {
if (!v8Native.lockV8Runtime(v8Runtime.getHandle())) {
throw new JavetException(JavetError.LockAcquisitionFailure);
}
+ locked = true;
}
@Override
@@ -61,5 +65,21 @@ public void close() throws JavetException {
if (!v8Native.unlockV8Runtime(v8Runtime.getHandle())) {
throw new JavetException(JavetError.LockReleaseFailure);
}
+ locked = false;
+ }
+
+ @Override
+ public boolean isClosed() {
+ return !locked;
+ }
+
+ /**
+ * Is locked.
+ *
+ * @return the boolean
+ * @since 0.9.10
+ */
+ public boolean isLocked() {
+ return locked;
}
}
diff --git a/src/main/java/com/caoccao/javet/interop/V8Runtime.java b/src/main/java/com/caoccao/javet/interop/V8Runtime.java
index a231aa63d..bbd7c0e74 100644
--- a/src/main/java/com/caoccao/javet/interop/V8Runtime.java
+++ b/src/main/java/com/caoccao/javet/interop/V8Runtime.java
@@ -158,7 +158,7 @@ public void close() throws JavetException {
}
public void close(boolean forceClose) throws JavetException {
- if (handle != INVALID_HANDLE && forceClose) {
+ if (!isClosed() && forceClose) {
removeAllReferences();
v8Host.closeV8Runtime(this);
handle = INVALID_HANDLE;
@@ -541,7 +541,7 @@ public boolean hasOwnProperty(IV8ValueObject iV8ValueObject, V8Value key) throws
* @param deadlineInMillis the deadline in millis
*/
public void idleNotificationDeadline(long deadlineInMillis) {
- if (handle != INVALID_HANDLE && deadlineInMillis > 0) {
+ if (!isClosed() && deadlineInMillis > 0) {
v8Native.idleNotificationDeadline(handle, deadlineInMillis);
}
}
@@ -576,6 +576,11 @@ public T invoke(
handle, iV8ValueObject.getHandle(), iV8ValueObject.getType().getId(), functionName, returnResult, v8Values));
}
+ @Override
+ public boolean isClosed() {
+ return handle == INVALID_HANDLE;
+ }
+
public boolean isDead() {
return v8Native.isDead(handle);
}
@@ -600,7 +605,7 @@ public boolean isWeak(IV8ValueReference iV8ValueReference) {
* Send low memory notification to current V8 isolate.
*/
public void lowMemoryNotification() {
- if (handle != INVALID_HANDLE) {
+ if (!isClosed()) {
v8Native.lowMemoryNotification(handle);
}
}
@@ -735,7 +740,7 @@ protected void removeCallbackContexts() {
}
public void removeJNIGlobalRef(long handle) {
- if (handle != INVALID_HANDLE) {
+ if (!isClosed()) {
v8Native.removeJNIGlobalRef(handle);
}
}
diff --git a/src/main/java/com/caoccao/javet/interop/engine/JavetEngine.java b/src/main/java/com/caoccao/javet/interop/engine/JavetEngine.java
index 425cf9bbe..cc7b0f0c8 100644
--- a/src/main/java/com/caoccao/javet/interop/engine/JavetEngine.java
+++ b/src/main/java/com/caoccao/javet/interop/engine/JavetEngine.java
@@ -97,6 +97,11 @@ public boolean isActive() {
return active;
}
+ @Override
+ public boolean isClosed() {
+ return v8Runtime == null || v8Runtime.isClosed();
+ }
+
@Override
public void resetContext() throws JavetException {
v8Runtime.resetContext();
diff --git a/src/main/java/com/caoccao/javet/interop/engine/JavetEngineGuard.java b/src/main/java/com/caoccao/javet/interop/engine/JavetEngineGuard.java
index 774a79215..cc56f5d62 100644
--- a/src/main/java/com/caoccao/javet/interop/engine/JavetEngineGuard.java
+++ b/src/main/java/com/caoccao/javet/interop/engine/JavetEngineGuard.java
@@ -29,19 +29,74 @@
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
+/**
+ * The type Javet engine guard.
+ *
+ * @since 0.7.2
+ */
public class JavetEngineGuard implements IJavetEngineGuard {
+ /**
+ * The constant IS_IN_DEBUG_MODE.
+ *
+ * @since 0.8.9
+ */
protected static final boolean IS_IN_DEBUG_MODE = ManagementFactory.getRuntimeMXBean().
getInputArguments().toString().indexOf("-agentlib:jdwp") > 0;
+ /**
+ * The Closed.
+ *
+ * @since 0.9.10
+ */
+ protected boolean closed;
+ /**
+ * The Future.
+ *
+ * @since 0.8.10
+ */
protected Future> future;
+ /**
+ * The Javet engine.
+ *
+ * @since 0.8.10
+ */
protected IJavetEngine> iJavetEngine;
+ /**
+ * The Quitting.
+ *
+ * @since 0.8.10
+ */
protected volatile boolean quitting;
+ /**
+ * The Skip in debug mode.
+ *
+ * @since 0.8.9
+ */
protected boolean skipInDebugMode;
+ /**
+ * The Timeout millis.
+ *
+ * @since 0.8.9
+ */
protected long timeoutMillis;
+ /**
+ * The V8 runtime.
+ *
+ * @since 0.7.2
+ */
protected V8Runtime v8Runtime;
+ /**
+ * Instantiates a new Javet engine guard.
+ *
+ * @param iJavetEngine the javet engine
+ * @param v8Runtime the V8 runtime
+ * @param timeoutMills the timeout mills
+ * @since 0.7.2
+ */
public JavetEngineGuard(IJavetEngine> iJavetEngine, V8Runtime v8Runtime, long timeoutMills) {
Objects.requireNonNull(iJavetEngine);
+ closed = false;
this.iJavetEngine = iJavetEngine;
quitting = false;
skipInDebugMode = true;
@@ -61,6 +116,7 @@ public void close() throws JavetException {
if (!future.isDone() && !future.isCancelled()) {
future.cancel(true);
}
+ closed = true;
}
@Override
@@ -78,10 +134,27 @@ public long getTimeoutMillis() {
return timeoutMillis;
}
+ /**
+ * Gets utc now.
+ *
+ * @return the utc now
+ * @since 0.9.1
+ */
protected ZonedDateTime getUTCNow() {
return JavetDateTimeUtils.getUTCNow();
}
+ @Override
+ public boolean isClosed() {
+ return closed || v8Runtime == null || v8Runtime.isClosed();
+ }
+
+ /**
+ * Is quitting boolean.
+ *
+ * @return the boolean
+ * @since 0.7.2
+ */
public boolean isQuitting() {
return quitting;
}
diff --git a/src/main/java/com/caoccao/javet/interop/engine/JavetEnginePool.java b/src/main/java/com/caoccao/javet/interop/engine/JavetEnginePool.java
index 36373f696..8e1648ece 100644
--- a/src/main/java/com/caoccao/javet/interop/engine/JavetEnginePool.java
+++ b/src/main/java/com/caoccao/javet/interop/engine/JavetEnginePool.java
@@ -30,20 +30,77 @@
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
+/**
+ * The type Javet engine pool.
+ *
+ * @param the type parameter
+ * @since 0.8.0
+ */
public class JavetEnginePool implements IJavetEnginePool, Runnable {
+ /**
+ * The constant JAVET_DAEMON_THREAD_NAME.
+ *
+ * @since 0.8.10
+ */
protected static final String JAVET_DAEMON_THREAD_NAME = "Javet Daemon";
+ /**
+ * The Active engine list.
+ *
+ * @since 0.9.1
+ */
protected final ConcurrentLinkedQueue> activeEngineList;
+ /**
+ * The External lock.
+ *
+ * @since 0.8.10
+ */
protected final Object externalLock;
+ /**
+ * The Idle engine list.
+ *
+ * @since 0.9.1
+ */
protected final ConcurrentLinkedQueue> idleEngineList;
+ /**
+ * The Active.
+ *
+ * @since 0.7.0
+ */
protected volatile boolean active;
+ /**
+ * The Config.
+ *
+ * @since 0.7.0
+ */
protected JavetEngineConfig config;
+ /**
+ * The Daemon thread.
+ *
+ * @since 0.7.0
+ */
protected Thread daemonThread;
+ /**
+ * The Quitting.
+ *
+ * @since 0.7.0
+ */
protected volatile boolean quitting;
+ /**
+ * Instantiates a new Javet engine pool.
+ *
+ * @since 0.7.0
+ */
public JavetEnginePool() {
this(new JavetEngineConfig());
}
+ /**
+ * Instantiates a new Javet engine pool.
+ *
+ * @param config the config
+ * @since 0.7.0
+ */
public JavetEnginePool(JavetEngineConfig config) {
Objects.requireNonNull(config);
this.config = config;
@@ -60,6 +117,13 @@ public void close() throws JavetException {
stopDaemon();
}
+ /**
+ * Create engine javet engine.
+ *
+ * @return the javet engine
+ * @throws JavetException the javet exception
+ * @since 0.7.0
+ */
protected JavetEngine createEngine() throws JavetException {
V8Host v8Host = V8Host.getInstance(config.getJSRuntimeType());
@SuppressWarnings("ConstantConditions")
@@ -112,6 +176,12 @@ public int getIdleEngineCount() {
return idleEngineList.size();
}
+ /**
+ * Gets utc now.
+ *
+ * @return the utc now
+ * @since 0.7.0
+ */
protected ZonedDateTime getUTCNow() {
return JavetDateTimeUtils.getUTCNow();
}
@@ -121,6 +191,11 @@ public boolean isActive() {
return active;
}
+ @Override
+ public boolean isClosed() {
+ return !active;
+ }
+
@Override
public boolean isQuitting() {
return quitting;
@@ -224,6 +299,11 @@ public void run() {
logger.debug("JavetEnginePool.run() ends.");
}
+ /**
+ * Start daemon.
+ *
+ * @since 0.7.0
+ */
protected void startDaemon() {
IJavetLogger logger = config.getJavetLogger();
logger.debug("JavetEnginePool.startDaemon() begins.");
@@ -239,6 +319,11 @@ protected void startDaemon() {
logger.debug("JavetEnginePool.startDaemon() ends.");
}
+ /**
+ * Stop daemon.
+ *
+ * @since 0.7.0
+ */
protected void stopDaemon() {
IJavetLogger logger = config.getJavetLogger();
logger.debug("JavetEnginePool.stopDaemon() begins.");
diff --git a/src/main/java/com/caoccao/javet/interop/proxy/DynamicProxyV8ValueFunctionInvocationHandler.java b/src/main/java/com/caoccao/javet/interop/proxy/DynamicProxyV8ValueFunctionInvocationHandler.java
new file mode 100644
index 000000000..b9832c5f0
--- /dev/null
+++ b/src/main/java/com/caoccao/javet/interop/proxy/DynamicProxyV8ValueFunctionInvocationHandler.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2021. caoccao.com Sam Cao
+ * All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.caoccao.javet.interop.proxy;
+
+import com.caoccao.javet.exceptions.JavetException;
+import com.caoccao.javet.interfaces.IJavetClosable;
+import com.caoccao.javet.utils.JavetResourceUtils;
+import com.caoccao.javet.values.reference.V8ValueFunction;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+
+/**
+ * The type Dynamic proxy V8 value function invocation handler.
+ */
+public class DynamicProxyV8ValueFunctionInvocationHandler implements InvocationHandler, IJavetClosable {
+ private static final String METHOD_NAME_CLOSE = "close";
+ private V8ValueFunction v8ValueFunction;
+
+ /**
+ * Instantiates a new Dynamic proxy V8 value function invocation handler.
+ *
+ * @param v8ValueFunction the V8 value function
+ * @since 0.9.10
+ */
+ public DynamicProxyV8ValueFunctionInvocationHandler(V8ValueFunction v8ValueFunction) {
+ this.v8ValueFunction = v8ValueFunction;
+ }
+
+ @Override
+ public void close() throws JavetException {
+ JavetResourceUtils.safeClose(v8ValueFunction);
+ v8ValueFunction = null;
+ }
+
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ Object result = null;
+ if (args == null) {
+ args = new Object[0];
+ }
+ if (method.getName().equals(METHOD_NAME_CLOSE) && args.length == 0) {
+ close();
+ } else if (v8ValueFunction != null && !v8ValueFunction.isClosed()) {
+ result = v8ValueFunction.callObject(null, args);
+ }
+ return result;
+ }
+
+ @Override
+ public boolean isClosed() {
+ return v8ValueFunction == null || v8ValueFunction.isClosed();
+ }
+}
diff --git a/src/main/java/com/caoccao/javet/interop/proxy/DynamicProxyV8ValueObjectInvocationHandler.java b/src/main/java/com/caoccao/javet/interop/proxy/DynamicProxyV8ValueObjectInvocationHandler.java
new file mode 100644
index 000000000..2b320214b
--- /dev/null
+++ b/src/main/java/com/caoccao/javet/interop/proxy/DynamicProxyV8ValueObjectInvocationHandler.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2021. caoccao.com Sam Cao
+ * All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.caoccao.javet.interop.proxy;
+
+import com.caoccao.javet.exceptions.JavetException;
+import com.caoccao.javet.interfaces.IJavetClosable;
+import com.caoccao.javet.utils.JavetResourceUtils;
+import com.caoccao.javet.values.reference.V8ValueObject;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+
+/**
+ * The type Dynamic proxy V8 value object invocation handler.
+ */
+public class DynamicProxyV8ValueObjectInvocationHandler implements InvocationHandler, IJavetClosable {
+ private static final String METHOD_NAME_CLOSE = "close";
+ private V8ValueObject v8ValueObject;
+
+ /**
+ * Instantiates a new Dynamic proxy V8 value object invocation handler.
+ *
+ * @param v8ValueObject the V8 value object
+ * @since 0.9.10
+ */
+ public DynamicProxyV8ValueObjectInvocationHandler(V8ValueObject v8ValueObject) {
+ this.v8ValueObject = v8ValueObject;
+ }
+
+ @Override
+ public void close() throws JavetException {
+ JavetResourceUtils.safeClose(v8ValueObject);
+ v8ValueObject = null;
+ }
+
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ Object result = null;
+ if (args == null) {
+ args = new Object[0];
+ }
+ if (method.getName().equals(METHOD_NAME_CLOSE) && args.length == 0) {
+ close();
+ } else if (v8ValueObject != null && !v8ValueObject.isClosed()) {
+ result = v8ValueObject.invokeObject(method.getName(), args);
+ }
+ return result;
+ }
+
+ @Override
+ public boolean isClosed() {
+ return v8ValueObject == null || v8ValueObject.isClosed();
+ }
+}
diff --git a/src/main/java/com/caoccao/javet/interop/proxy/JavetUniversalProxyHandler.java b/src/main/java/com/caoccao/javet/interop/proxy/JavetUniversalProxyHandler.java
index 9a510ea14..174aa5cbd 100644
--- a/src/main/java/com/caoccao/javet/interop/proxy/JavetUniversalProxyHandler.java
+++ b/src/main/java/com/caoccao/javet/interop/proxy/JavetUniversalProxyHandler.java
@@ -23,13 +23,14 @@
import com.caoccao.javet.exceptions.JavetException;
import com.caoccao.javet.interop.V8Runtime;
import com.caoccao.javet.interop.callback.JavetCallbackContext;
-import com.caoccao.javet.utils.JavetPrimitiveUtils;
-import com.caoccao.javet.utils.JavetReflectionUtils;
-import com.caoccao.javet.utils.SimpleMap;
+import com.caoccao.javet.utils.*;
import com.caoccao.javet.values.V8Value;
import com.caoccao.javet.values.primitive.V8ValueBoolean;
import com.caoccao.javet.values.primitive.V8ValueString;
import com.caoccao.javet.values.reference.V8ValueArray;
+import com.caoccao.javet.values.reference.V8ValueFunction;
+import com.caoccao.javet.values.reference.V8ValueObject;
+import com.caoccao.javet.values.reference.V8ValueProxy;
import java.lang.reflect.*;
import java.util.*;
@@ -75,6 +76,30 @@ public class JavetUniversalProxyHandler extends BaseJavetProxyHandler {
* @since 0.9.6
*/
protected static final String[] SETTER_PREFIX_ARRAY = new String[]{"set", "put"};
+ /**
+ * The constant V8_VALUE_CLASS.
+ *
+ * @since 0.9.10
+ */
+ protected static final Class> V8_VALUE_CLASS = V8Value.class;
+ /**
+ * The constant V8_VALUE_FUNCTION_CLASS.
+ *
+ * @since 0.9.10
+ */
+ protected static final Class> V8_VALUE_FUNCTION_CLASS = V8ValueFunction.class;
+ /**
+ * The constant V8_VALUE_OBJECT_CLASS.
+ *
+ * @since 0.9.10
+ */
+ protected static final Class> V8_VALUE_OBJECT_CLASS = V8ValueObject.class;
+ /**
+ * The constant V8_VALUE_PROXY_CLASS.
+ *
+ * @since 0.9.10
+ */
+ protected static final Class> V8_VALUE_PROXY_CLASS = V8ValueProxy.class;
/**
* The Class mode.
*
@@ -162,85 +187,43 @@ public JavetUniversalProxyHandler(V8Runtime v8Runtime, T targetObject) {
}
/**
- * Calculate score double.
+ * Execute.
*
- * @param executable the executable
- * @param objects the objects
- * @return the score
- * @since 0.9.8
+ * @param the type parameter
+ * @param v8Runtime the V8 runtime
+ * @param targetObject the target object
+ * @param executables the executables
+ * @param javetVirtualObjects the javet virtual objects
+ * @return the object
+ * @throws Throwable the throwable
+ * @since 0.9.10
*/
- protected static double calculateScore(Executable executable, Object... objects) {
- // Max score is 1. Min score is 0.
- final int parameterCount = executable.getParameterCount();
- Class>[] parameterTypes = executable.getParameterTypes();
- boolean isMethodVarArgs = executable.isVarArgs();
- double score = 0;
- final int length = objects.length;
- if (length == 0) {
- if (isMethodVarArgs) {
- if (parameterCount == 1) {
- score = 0.99;
- }
- } else {
- if (parameterCount == 0) {
- score = 1;
- }
+ protected static Object execute(
+ V8Runtime v8Runtime, Object targetObject, List executables, JavetVirtualObject[] javetVirtualObjects)
+ throws Throwable {
+ List> scoredExecutables = new ArrayList<>();
+ for (E executable : executables) {
+ ScoredExecutable scoredExecutable = new ScoredExecutable(
+ v8Runtime, targetObject, executable, javetVirtualObjects);
+ scoredExecutable.calculateScore();
+ double score = scoredExecutable.getScore();
+ if (score > 0) {
+ scoredExecutables.add(scoredExecutable);
}
- } else {
- boolean isVarArgs = isMethodVarArgs && length >= parameterCount - 1;
- boolean isFixedArgs = !isMethodVarArgs && length == parameterCount;
- if (isVarArgs || isFixedArgs) {
- double totalScore = 0;
- final int fixedParameterCount = isMethodVarArgs ? parameterCount - 1 : parameterCount;
- for (int i = 0; i < fixedParameterCount; i++) {
- Class> parameterType = parameterTypes[i];
- Object object = objects[i];
- if (object == null) {
- if (parameterType.isPrimitive()) {
- totalScore = 0;
- break;
- } else {
- totalScore += 1;
- }
- } else if (parameterType.isAssignableFrom(object.getClass())) {
- totalScore += 1;
- } else if (parameterType.isPrimitive()
- && JavetPrimitiveUtils.toExactPrimitive(parameterType, object) != null) {
- totalScore += 0.9;
- } else {
- totalScore = 0;
- break;
- }
- }
- if ((fixedParameterCount == 0 || (fixedParameterCount > 0 && totalScore > 0))
- && isMethodVarArgs && length >= parameterCount) {
- Class> componentType = parameterTypes[fixedParameterCount].getComponentType();
- for (int i = fixedParameterCount; i < length; ++i) {
- Object object = objects[i];
- if (object == null) {
- if (componentType.isPrimitive()) {
- totalScore = 0;
- break;
- } else {
- totalScore += 1;
- }
- } else if (componentType.isAssignableFrom(object.getClass())) {
- totalScore += 1;
- } else if (componentType.isPrimitive()
- && JavetPrimitiveUtils.toExactPrimitive(componentType, object) != null) {
- totalScore += 0.8;
- } else {
- totalScore = 0;
- break;
- }
- }
- }
- if (totalScore > 0) {
- score = totalScore / length;
+ }
+ if (!scoredExecutables.isEmpty()) {
+ scoredExecutables.sort((o1, o2) -> Double.compare(o2.getScore(), o1.getScore()));
+ Throwable lastException = null;
+ for (ScoredExecutable scoredExecutable : scoredExecutables) {
+ try {
+ return scoredExecutable.execute();
+ } catch (Throwable t) {
+ lastException = t;
}
}
+ throw lastException;
}
- return score;
+ return null;
}
/**
@@ -287,81 +270,21 @@ protected void addMethod(Method method, int startIndex, Map
@V8Function
@Override
public V8Value construct(V8Value target, V8ValueArray arguments, V8Value newTarget) throws JavetException {
- Object[] objects = ((ArrayList) v8Runtime.toObject(arguments)).toArray();
- final int length = objects.length;
- List> sortedConstructors = new ArrayList<>();
- for (Constructor constructor : constructors) {
- double score = calculateScore(constructor, objects);
- if (score > 0) {
- sortedConstructors.add(new ScoredExecutable(score, constructor));
- }
- }
- if (!sortedConstructors.isEmpty()) {
- sortedConstructors.sort((o1, o2) -> Double.compare(o2.getScore(), o1.getScore()));
- Throwable lastException = null;
- for (ScoredExecutable scoredConstructor : sortedConstructors) {
- Constructor constructor = scoredConstructor.getExecutable();
- final int parameterCount = constructor.getParameterCount();
- Class>[] parameterTypes = constructor.getParameterTypes();
- boolean isMethodVarArgs = constructor.isVarArgs();
- try {
- if (length == 0) {
- if (isMethodVarArgs) {
- Class> componentType = parameterTypes[parameterCount - 1];
- Object varObject = Array.newInstance(componentType, 0);
- return v8Runtime.toV8Value(constructor.newInstance(varObject));
- } else {
- return v8Runtime.toV8Value(constructor.newInstance());
- }
- } else {
- List