tag:blogger.com,1999:blog-66020544142156837482024-03-06T12:40:32.614+08:00Sam Cao's BlogSam Caohttp://www.blogger.com/profile/03721092279920165184noreply@blogger.comBlogger34125tag:blogger.com,1999:blog-6602054414215683748.post-27160022016686082562024-01-25T17:21:00.003+08:002024-01-27T06:37:44.912+08:00Cue Club 2 on Apple Silicon<p><span face=""Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif" style="background-color: white; color: #333333; font-size: 16px;">It's been quite a long time for me not to play a decent snooker game since I replaced my Windows laptop with an Apple Silicon one. To be more specific, the Cue Club 2 on Steam is the one. However, it only supports Windows. In this article, I'll share you how to set up this game on Apple Silicon.</span></p><h2 data-source-line="5" id="environment" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 #0000; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; font-size: 1.75em; line-height: 1.2; margin-bottom: 16px; margin-top: 1em; padding-bottom: 0.3em;">Environment</h2><ul data-source-line="7" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 #0000; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; color: #333333; font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; font-size: 16px; list-style-image: initial; list-style-position: initial; margin-bottom: 16px; margin-top: 0px; padding-left: 2em;"><li data-source-line="7" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 #0000; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; margin-bottom: 0px;">MacBook Pro M2 Max</li><li data-source-line="8" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 #0000; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; margin-bottom: 0px;">64GB RAM</li></ul><h2 data-source-line="10" id="1-install-vmware-fusion" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 #0000; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; font-size: 1.75em; line-height: 1.2; margin-bottom: 16px; margin-top: 1em; padding-bottom: 0.3em;">1. Install VMware Fusion</h2><p class="highlight-line" data-source-line="12" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 #0000; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; color: #333333; font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; font-size: 16px; margin-bottom: 16px; margin-top: 0px; position: relative;">VMware Fusion is the Desktop Hypervisors for Mac with all-new Windows 11 support on Macs with Apple silicon. It offers a free version of personal use license. Just visit the official <a href="https://www.vmware.com/products/fusion.html" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 #0000; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; color: #0088cc; text-decoration-line: none;">website</a> to install it.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsdEJ7GNE4O6y93H0nWq-_aX5bZNIox4mMzpTWzVVEUZ-FRW0jLTjXa6JZqUDNCo2OsM1nQlSUd6-LZFUs8XbZzU82dk1OQp5sZLxLcyCA-4R6kVc6D1BfywFa0RlsqEVtvELmGwouPD6mctnSMBICA16NUzPkzKl5TwZ0O-cnDWE04ej8B-ek5Oh4Qgg/s2048/vmware.fusion.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1332" data-original-width="2048" height="416" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsdEJ7GNE4O6y93H0nWq-_aX5bZNIox4mMzpTWzVVEUZ-FRW0jLTjXa6JZqUDNCo2OsM1nQlSUd6-LZFUs8XbZzU82dk1OQp5sZLxLcyCA-4R6kVc6D1BfywFa0RlsqEVtvELmGwouPD6mctnSMBICA16NUzPkzKl5TwZ0O-cnDWE04ej8B-ek5Oh4Qgg/w640-h416/vmware.fusion.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: left;"><span face=""Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif" style="background-color: white; color: #333333; font-size: 16px;">Apply for a personal use license.</span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj08m9-uOZz2fdM1NwcNfHqQPXUXvjnmXRRYai6s9QQZL2J6CTfxQX7a9Vo9lcT1mw_87Zf1YGhUxauyi9eIz-z8XtOSskLthLyU89OQN64dLt3DYXN3ZvnAeB_tXvWsZKcyvLxL7LN90g4bWsrtkgdB5MBAIdUQ6Wvc-Ol9bf8qtlFB-1mZ6-x_vB_BnY/s1374/license.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="866" data-original-width="1374" height="253" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj08m9-uOZz2fdM1NwcNfHqQPXUXvjnmXRRYai6s9QQZL2J6CTfxQX7a9Vo9lcT1mw_87Zf1YGhUxauyi9eIz-z8XtOSskLthLyU89OQN64dLt3DYXN3ZvnAeB_tXvWsZKcyvLxL7LN90g4bWsrtkgdB5MBAIdUQ6Wvc-Ol9bf8qtlFB-1mZ6-x_vB_BnY/w400-h253/license.png" width="400" /></a></div><h2 data-source-line="20" id="2-install-steam" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 #0000; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; font-size: 1.75em; line-height: 1.2; margin-bottom: 16px; margin-top: 1em; padding-bottom: 0.3em;">2. Install Windows 11</h2><p class="highlight-line" data-source-line="22" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 #0000; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; color: #333333; font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; font-size: 16px; margin-bottom: 16px; margin-top: 0px; position: relative;">Follow the official instructions to install Windows 11 arm64.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYrppxMbxsuCTgVdv-NmzSCZIfOdY2mZOVwNo18pvRBuNE6Y7nJrjLzgA1VMuefUoAMxAXk4VehopyQbXuLhmzFPwEsf94Qs7YK97npYxLnLnGaKbulEKY-bJFX2xz8mZXIrvYb2lFdyOzbC7iVPZR8j0M3sQRlUfkt7DI0lbn09oKWL20AExM5PGmguE/s2136/windows.11.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1446" data-original-width="2136" height="434" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYrppxMbxsuCTgVdv-NmzSCZIfOdY2mZOVwNo18pvRBuNE6Y7nJrjLzgA1VMuefUoAMxAXk4VehopyQbXuLhmzFPwEsf94Qs7YK97npYxLnLnGaKbulEKY-bJFX2xz8mZXIrvYb2lFdyOzbC7iVPZR8j0M3sQRlUfkt7DI0lbn09oKWL20AExM5PGmguE/w640-h434/windows.11.png" width="640" /></a></div><h2 data-source-line="26" id="3-install-steam" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 #0000; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; font-size: 1.75em; line-height: 1.2; margin-bottom: 16px; margin-top: 1em; padding-bottom: 0.3em;">3. Install Steam</h2><p class="highlight-line" data-source-line="28" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 #0000; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; color: #333333; font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; font-size: 16px; margin-bottom: 16px; margin-top: 0px; position: relative;">Visit the official <a href="https://store.steampowered.com/" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 #0000; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; color: #0088cc; text-decoration-line: none;">website</a>, install the Steam, and install the game. Both Steam and the game are installed to <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 #0000; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: #f0f0f0; border-radius: 3px; color: black; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; font-size: 0.85em; padding: 0.2em 0px;">C:\Program Files (x86)\Steam</code>, though the Windows runs on arm64.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiX7gxLnfK1yENq7oQdOY3KgPUdFdCv01PwuFbih0Klg_ylNoYjAqpP1I5Syu_w-v6flooGh8UPl6DJSSb__bBLfqWVoUbbN8BE92squB5QItytIVu5_mmHXWwmX8dpobN2Qrn_lhCwgUm8ozL9Yjyi-J_3Q3WOfZX6NJKcOW4ce_RQk3qaMZLckDtEzqc/s3140/steam.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="2012" data-original-width="3140" height="410" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiX7gxLnfK1yENq7oQdOY3KgPUdFdCv01PwuFbih0Klg_ylNoYjAqpP1I5Syu_w-v6flooGh8UPl6DJSSb__bBLfqWVoUbbN8BE92squB5QItytIVu5_mmHXWwmX8dpobN2Qrn_lhCwgUm8ozL9Yjyi-J_3Q3WOfZX6NJKcOW4ce_RQk3qaMZLckDtEzqc/w640-h410/steam.png" width="640" /></a></div><h2 data-source-line="32" id="4-graphics-settings" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 #0000; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; font-size: 1.75em; line-height: 1.2; margin-bottom: 16px; margin-top: 1em; padding-bottom: 0.3em;">4. Graphics Settings</h2><p class="highlight-line" data-source-line="34" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 #0000; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; color: #333333; font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; font-size: 16px; margin-bottom: 16px; margin-top: 0px; position: relative;">Click the button [Play] to launch the game. Here is my preference on the screen resolution for your reference.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiERGK1-jefyw1q7entNCAijqjA-aTCnhbuyqbrioWNQf5iWXL8Z3X9Qfjw2haqMpdEod0A8CHjSxLkOPSCjfCcnDsUsurNNQZ5JAoEi1Cb1iZaCw-ie-OMBsJmPI6CwaXxEXSqQrNnFJoBu_oqQoT8aXisdDENmo-UAMzoVERIKmBObkBE_iM9gRxF1oQ/s3140/graphics.settings.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="2012" data-original-width="3140" height="410" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiERGK1-jefyw1q7entNCAijqjA-aTCnhbuyqbrioWNQf5iWXL8Z3X9Qfjw2haqMpdEod0A8CHjSxLkOPSCjfCcnDsUsurNNQZ5JAoEi1Cb1iZaCw-ie-OMBsJmPI6CwaXxEXSqQrNnFJoBu_oqQoT8aXisdDENmo-UAMzoVERIKmBObkBE_iM9gRxF1oQ/w640-h410/graphics.settings.png" width="640" /></a></div><p data-source-line="38" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 #0000; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; color: #333333; font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; font-size: 16px; margin-bottom: 16px; margin-top: 0px;">It's better not to turn on the VMware Fusion full screen mode, because the game may crash.</p><h2 class="highlight-line" data-source-line="40" id="enjoy-the-game" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 #0000; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; font-size: 1.75em; line-height: 1.2; margin-bottom: 16px; margin-top: 1em; padding-bottom: 0.3em; position: relative;">Enjoy the Game</h2><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvoI8eEHltQRwESWtw2fH1eOOlDgrP0Eq-L19by4uIL0kuhg08l2QlSffqdZimK4zlO1ajXWYHkQde-9Nn8Ix1waYYQGA3knLu7Hdry9mtopLdHFzrSKkZwCRg_4OvicEV4pbQSOroLgWKGxBrJqpzXdHrzLZBGwgEVBVlquY4omulH8xuG3_mBeSbGSM/s3140/2d.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="2012" data-original-width="3140" height="410" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvoI8eEHltQRwESWtw2fH1eOOlDgrP0Eq-L19by4uIL0kuhg08l2QlSffqdZimK4zlO1ajXWYHkQde-9Nn8Ix1waYYQGA3knLu7Hdry9mtopLdHFzrSKkZwCRg_4OvicEV4pbQSOroLgWKGxBrJqpzXdHrzLZBGwgEVBVlquY4omulH8xuG3_mBeSbGSM/w640-h410/2d.png" width="640" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjknd6YPEddnq4L6a6cVuutiYh1GBPjXaH8SsZwtlyPh-LHoJ_a3yjf5yOEB8apP86gXeeq7kHVqXCz_yRMFyXEc3lXpibfQ_j5UE_IAE0hfTmL_aYJF3VE8othziOhjiNLPcX_CeS_bcjA32-Eu53SJA7VcyZ8axLVNj87zeAxkL3tlMrNOGYqMZkRqXs/s3140/3d.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="2012" data-original-width="3140" height="410" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjknd6YPEddnq4L6a6cVuutiYh1GBPjXaH8SsZwtlyPh-LHoJ_a3yjf5yOEB8apP86gXeeq7kHVqXCz_yRMFyXEc3lXpibfQ_j5UE_IAE0hfTmL_aYJF3VE8othziOhjiNLPcX_CeS_bcjA32-Eu53SJA7VcyZ8axLVNj87zeAxkL3tlMrNOGYqMZkRqXs/w640-h410/3d.png" width="640" /></a></div><br /><p class="highlight-line" data-source-line="12" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 #0000; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; color: #333333; font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; font-size: 16px; margin-bottom: 16px; margin-top: 0px; position: relative;"><br /></p>Sam Caohttp://www.blogger.com/profile/03721092279920165184noreply@blogger.com0tag:blogger.com,1999:blog-6602054414215683748.post-3906208821642490542023-09-08T16:05:00.003+08:002023-09-08T16:05:17.348+08:00Undefined Symbols in V8 Monolith<p><span style="background-color: white; color: #333333; font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; font-size: 16px;">There are many applications and libraries acting as embedders to Google V8 JavaScript engine. My open source project</span><span style="background-color: white; color: #333333; font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; font-size: 16px;"> </span><a href="https://github.com/caoccao/Javet/" style="color: #0088cc; font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; font-size: 16px; text-decoration-line: none;">Javet</a><span style="background-color: white; color: #333333; font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; font-size: 16px;"> </span><span style="background-color: white; color: #333333; font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; font-size: 16px;">is one of them. When I was about to upgrade to V8 v11.7, the build was broken. I'd like to share the troubleshooting story in this post with you.</span></p><p class="sync-line" data-line="4" style="background-color: white; color: #333333; font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; font-size: 16px; margin: 0px;"></p><h2 class="mume-header" id="undefined-symbols-absltime_internalcctzlocal_time_zone" style="background-color: white; font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; font-size: 1.75em; line-height: 1.2; margin-bottom: 16px; margin-top: 1em; padding-bottom: 0.3em;">Undefined symbols absl::time_internal::cctz::local_time_zone()</h2><p style="background-color: white; color: #333333; font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; font-size: 16px; margin-bottom: 16px; margin-top: 0px;">The Javet build on V8 v11.7 worked well on Windows, Linux and Android, but failed on Mac x86_64 and arm64 with the following cmake error logs.</p><p class="sync-line" data-line="8" style="background-color: white; color: #333333; font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; font-size: 16px; margin: 0px;"></p><pre class="language-text" data-info="text" data-role="codeBlock" style="background: rgb(245, 245, 245); border-radius: 3px; border: rgb(214, 214, 214); color: #333333; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 0.85em !important; hyphens: none; line-height: 1.4; margin-bottom: 16px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 0.8em; tab-size: 8; word-break: normal;">Undefined symbols for architecture x86_64:
"_CFRelease", referenced from:
absl::time_internal::cctz::local_time_zone() in libv8_monolith.a(time_zone_lookup.o)
"_CFStringGetCString", referenced from:
absl::time_internal::cctz::local_time_zone() in libv8_monolith.a(time_zone_lookup.o)
"_CFStringGetLength", referenced from:
absl::time_internal::cctz::local_time_zone() in libv8_monolith.a(time_zone_lookup.o)
"_CFStringGetMaximumSizeForEncoding", referenced from:
absl::time_internal::cctz::local_time_zone() in libv8_monolith.a(time_zone_lookup.o)
"_CFTimeZoneCopyDefault", referenced from:
absl::time_internal::cctz::local_time_zone() in libv8_monolith.a(time_zone_lookup.o)
"_CFTimeZoneGetName", referenced from:
absl::time_internal::cctz::local_time_zone() in libv8_monolith.a(time_zone_lookup.o)
ld: symbol(s) not found for architecture x86_64
</pre><p class="sync-line" data-line="25" style="background-color: white; color: #333333; font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; font-size: 16px; margin: 0px;"></p><pre class="language-text" data-info="text" data-role="codeBlock" style="background: rgb(245, 245, 245); border-radius: 3px; border: rgb(214, 214, 214); color: #333333; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 0.85em !important; hyphens: none; line-height: 1.4; margin-bottom: 16px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 0.8em; tab-size: 8; word-break: normal;">Undefined symbols for architecture arm64:
"_CFRelease", referenced from:
absl::time_internal::cctz::local_time_zone() in libv8_monolith.a(time_zone_lookup.o)
"_CFStringGetCString", referenced from:
absl::time_internal::cctz::local_time_zone() in libv8_monolith.a(time_zone_lookup.o)
"_CFStringGetLength", referenced from:
absl::time_internal::cctz::local_time_zone() in libv8_monolith.a(time_zone_lookup.o)
"_CFStringGetMaximumSizeForEncoding", referenced from:
absl::time_internal::cctz::local_time_zone() in libv8_monolith.a(time_zone_lookup.o)
"_CFTimeZoneCopyDefault", referenced from:
absl::time_internal::cctz::local_time_zone() in libv8_monolith.a(time_zone_lookup.o)
"_CFTimeZoneGetName", referenced from:
absl::time_internal::cctz::local_time_zone() in libv8_monolith.a(time_zone_lookup.o)
ld: symbol(s) not found for architecture arm64
</pre><p class="sync-line" data-line="42" style="background-color: white; color: #333333; font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; font-size: 16px; margin: 0px;"></p><h2 class="mume-header" id="analysis" style="background-color: white; font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; font-size: 1.75em; line-height: 1.2; margin-bottom: 16px; margin-top: 1em; padding-bottom: 0.3em;">Analysis</h2><p style="background-color: white; color: #333333; font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; font-size: 16px; margin-bottom: 16px; margin-top: 0px;">V8 has a build target called <code style="background-color: #f0f0f0; border-radius: 3px; color: black; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; font-size: 0.85em !important; padding: 0.2em 0px;">v8_monolith</code> which is for embedders. It usually has all the symbols built in <code style="background-color: #f0f0f0; border-radius: 3px; color: black; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; font-size: 0.85em !important; padding: 0.2em 0px;">libv8_monolith.a</code>. However it forgets to include <a href="https://github.com/abseil/abseil-cpp" style="color: #0088cc; text-decoration-line: none;">Abseil - C++ Common Libraries</a> as the error log shows undefined symbols during the link phase.</p><p style="background-color: white; color: #333333; font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; font-size: 16px; margin-bottom: 16px; margin-top: 0px;">So, the goal is to find or build those missing symbols for the linker to work properly.</p><p class="sync-line" data-line="48" style="background-color: white; color: #333333; font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; font-size: 16px; margin: 0px;"></p><h2 class="mume-header" id="solution" style="background-color: white; font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; font-size: 1.75em; line-height: 1.2; margin-bottom: 16px; margin-top: 1em; padding-bottom: 0.3em;">Solution</h2><p style="background-color: white; color: #333333; font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; font-size: 16px; margin-bottom: 16px; margin-top: 0px;">After going over the official <a href="https://github.com/abseil/abseil-cpp" style="color: #0088cc; text-decoration-line: none;">Abseil</a> doc, I found the solution at <a href="https://github.com/abseil/abseil-cpp/blob/master/CMake/README.md" style="color: #0088cc; text-decoration-line: none;">Abseil CMake Build Instructions</a>. Basically, I needed to add Abseil to the Javet <code style="background-color: #f0f0f0; border-radius: 3px; color: black; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; font-size: 0.85em !important; padding: 0.2em 0px;">CMakeList.txt</code> so that the linker won't complain anymore.</p><p class="sync-line" data-line="52" style="background-color: white; color: #333333; font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; font-size: 16px; margin: 0px;"></p><pre class="language-cmake" data-info="cmake" data-role="codeBlock" style="background: rgb(245, 245, 245); border-radius: 3px; border: rgb(214, 214, 214); color: #333333; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 0.85em !important; hyphens: none; line-height: 1.4; margin-bottom: 16px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 0.8em; tab-size: 8; word-break: normal;"><span class="token keyword keyword-add_subdirectory" style="color: #a71d5d;">add_subdirectory</span><span class="token punctuation">(</span><span class="token punctuation">${</span>V8_DIR<span class="token punctuation">}</span>/third_party/abseil-cpp <span class="token punctuation">${</span>V8_RELEASE_DIR<span class="token punctuation">}</span>/third_party/abseil-cpp<span class="token punctuation">)</span>
<span class="token keyword keyword-target_link_libraries" style="color: #a71d5d;">target_link_libraries</span><span class="token punctuation">(</span>Javet <span class="token namespace" style="color: #795da3;">PUBLIC</span> <span class="token inserted class-name" style="background-color: #eaffea; color: #55a532;">absl::base</span> <span class="token inserted class-name" style="background-color: #eaffea; color: #55a532;">absl::time</span><span class="token punctuation">)</span>
</pre><ul style="background-color: white; color: #333333; font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; font-size: 16px; margin-bottom: 16px; margin-top: 0px; padding-left: 2em;"><li style="margin-bottom: 0px;"><code style="background-color: #f0f0f0; border-radius: 3px; color: black; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; font-size: 0.85em !important; padding: 0.2em 0px;">${V8_DIR}</code> is the directory of the V8 source code.</li><li style="margin-bottom: 0px;"><code style="background-color: #f0f0f0; border-radius: 3px; color: black; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; font-size: 0.85em !important; padding: 0.2em 0px;">${V8_RELEASE_DIR}</code> is the directory of the build target.<ul style="margin-bottom: 0px; margin-top: 0px; padding-left: 2em;"><li style="margin-bottom: 0px;">x86_64: <code style="background-color: #f0f0f0; border-radius: 3px; color: black; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; font-size: 0.85em !important; padding: 0.2em 0px;">${V8_DIR}/out.gn/x64.release</code></li><li style="margin-bottom: 0px;">arm64: <code style="background-color: #f0f0f0; border-radius: 3px; color: black; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; font-size: 0.85em !important; padding: 0.2em 0px;">${V8_DIR}/out.gn/arm64.release</code></li></ul></li></ul><p style="background-color: white; color: #333333; font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; font-size: 16px; margin-bottom: 16px; margin-top: 0px;">After this patch was applied, the build and test passed.</p>Sam Caohttp://www.blogger.com/profile/03721092279920165184noreply@blogger.com1tag:blogger.com,1999:blog-6602054414215683748.post-7971894125903928842023-05-25T10:19:00.002+08:002023-05-25T10:30:40.295+08:00CAPEA_KPEAVIsolate or CUPEA_KPEAVIsolate?<p>I tried to build V8 monolith on Windows 10 for v11.4 and v11.5 recently. The builds were good. However, when I tried to build my app linking <span style="color: #2b00fe; font-family: courier;">v8_monolith.lib</span>, I got the following error messages.</p><blockquote><p><span style="font-family: courier;">javet_converter.obj : error LNK2019: unresolved external symbol "private: static unsigned __int64 * __cdecl v8::internal::HandleScope::Extend(class v8::internal::Isolate *)" (?Extend @HandleScope@internal@v8@@<span style="color: red;"><b>CAPEA_KPEAVIsolate</b></span>@23@@Z) referenced in function "class _jobject * __cdecl Javet::Converter::ToExternalV8Value(struct JNIEnv_ *,class Javet::V8Runtime const *,class v8::Local<class v8::Context> const &,class v8::internal::Object const &)" (?ToExternalV8Value@Converter@Javet@@YAPEAV_jobject@@PEAUJNIEnv_@@PEBVV8Runtime@2@AEBV?$Local@VCont ext@v8@@@v8@@AEBVObject@internal@7@@Z)</span></p></blockquote><p>I located the symbols via dumpbin and found the highlighted one actually is <span style="font-family: courier;"><span style="color: red;"><b>CUPEA_KPEAVIsolate</b></span></span>.</p><p>I'm not sure what caused the corrupted V8 build. I fixed it by binary searching and replacing <span style="color: #2b00fe; font-family: courier;">CUPEA_KPEAVIsolate</span> with <span style="color: #2b00fe; font-family: courier;">CAPEA_KPEAVIsolate</span>, and it works.</p>Sam Caohttp://www.blogger.com/profile/03721092279920165184noreply@blogger.com0tag:blogger.com,1999:blog-6602054414215683748.post-18623108244395287952022-07-05T14:15:00.001+08:002022-07-05T14:53:59.771+08:00Serialize and Deserialize PageImpl in Jackson<p>It's very common to put paginated query results in Redis via Jackson serialization and deserialization. However, <span style="color: #2b00fe; font-family: courier;">org.springframework.data.domain.PageImpl</span> doesn't expose a default constructor. Even worse, that applies to <span style="color: #2b00fe; font-family: courier;">org.springframework.data.domain.Sort</span> and <span style="color: #2b00fe; font-family: courier;">org.springframework.data.domain.Sort.Order</span> as well. There are a couple of workarounds. I'd like to introduce a less intrusive approach for your reference.</p><p>The idea is to write a Jackson module which injects a custom serializer and deserializer for <span style="color: #2b00fe; font-family: courier;">org.springframework.data.domain.PageImpl</span>. Let's see how to do that.</p><p>1. Define an interface.</p><pre style="padding: 5px; background-color: #2b2b2b; color: #a9b7c6; font-family: "Fira Code", monospace, courier;"><span style="color: #cc7832;">public interface </span>IJPADataPage <span style="color: #e8ba36;">{<br /></span><span style="color: #e8ba36;"> </span>String <span style="color: #9876aa; font-style: italic;">_CLASS </span>= <span style="color: #6a8759;">"@class"</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> </span>String <span style="color: #9876aa; font-style: italic;">CONTENT </span>= <span style="color: #6a8759;">"content"</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> </span>String <span style="color: #9876aa; font-style: italic;">DIRECTION </span>= <span style="color: #6a8759;">"direction"</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> </span>String <span style="color: #9876aa; font-style: italic;">IGNORE_CASE </span>= <span style="color: #6a8759;">"ignoreCase"</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> </span>String <span style="color: #9876aa; font-style: italic;">NULL_HANDLING </span>= <span style="color: #6a8759;">"nullHandling"</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> </span>String <span style="color: #9876aa; font-style: italic;">NUMBER </span>= <span style="color: #6a8759;">"number"</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> </span>String <span style="color: #9876aa; font-style: italic;">PROPERTY </span>= <span style="color: #6a8759;">"property"</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> </span>String <span style="color: #9876aa; font-style: italic;">SIZE </span>= <span style="color: #6a8759;">"size"</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> </span>String <span style="color: #9876aa; font-style: italic;">SORT </span>= <span style="color: #6a8759;">"sort"</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> </span>String <span style="color: #9876aa; font-style: italic;">TOTAL_ELEMENTS </span>= <span style="color: #6a8759;">"totalElements"</span><span style="color: #cc7832;">;<br /></span><span style="color: #e8ba36;">}<br /></span></pre><p>2. Define a Serializer.</p><pre style="padding: 5px; background-color: #2b2b2b; color: #a9b7c6; font-family: "Fira Code", monospace, courier;"><span style="color: #cc7832;">import </span>com.fasterxml.jackson.core.JsonGenerator<span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;">import </span>com.fasterxml.jackson.databind.SerializerProvider<span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;">import </span>com.fasterxml.jackson.databind.jsontype.TypeSerializer<span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;">import </span>com.fasterxml.jackson.databind.ser.std.StdSerializer<span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;">import </span>org.springframework.data.domain.PageImpl<span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;">import </span>org.springframework.data.domain.Sort<span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"><br /></span><span style="color: #cc7832;">import </span>java.io.IOException<span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"><br /></span><span style="color: #bbb529;">@SuppressWarnings</span><span style="color: #e8ba36;">(</span><span style="color: #6a8759;">"unchecked"</span><span style="color: #e8ba36;">)<br /></span><span style="color: #cc7832;">public class </span>JPADataPageSerializer
<span style="color: #cc7832;">extends </span>StdSerializer<span style="color: #e8ba36;"><</span>PageImpl<span style="color: #e8ba36;">>
</span><span style="color: #cc7832;">implements </span>IJPADataPage <span style="color: #e8ba36;">{<br /></span><span style="color: #e8ba36;"> </span><span style="color: #cc7832;">public </span><span style="color: #ffc66d;">JPADataPageSerializer</span><span style="color: #e8ba36;">(</span>Class<span style="color: #e8ba36;"><</span>PageImpl<span style="color: #e8ba36;">> </span>t<span style="color: #e8ba36;">) </span><span style="color: #54a857;">{<br /></span><span style="color: #54a857;"> </span><span style="color: #cc7832;">super</span><span style="color: #e8ba36;">(</span>t<span style="color: #e8ba36;">)</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> </span><span style="color: #54a857;">}<br /></span><span style="color: #54a857;"><br /></span><span style="color: #54a857;"> </span><span style="color: #cc7832;">public </span><span style="color: #ffc66d;">JPADataPageSerializer</span><span style="color: #e8ba36;">() </span><span style="color: #54a857;">{<br /></span><span style="color: #54a857;"> </span><span style="color: #cc7832;">this</span><span style="color: #e8ba36;">(</span><span style="color: #cc7832;">null</span><span style="color: #e8ba36;">)</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> </span><span style="color: #54a857;">}<br /></span><span style="color: #54a857;"><br /></span><span style="color: #54a857;"> </span><span style="color: #bbb529;">@Override<br /></span><span style="color: #bbb529;"> </span><span style="color: #cc7832;">public void </span><span style="color: #ffc66d;">serialize</span><span style="color: #e8ba36;">(<br /></span><span style="color: #e8ba36;"> </span>PageImpl value<span style="color: #cc7832;">,<br /></span><span style="color: #cc7832;"> </span>JsonGenerator jsonGenerator<span style="color: #cc7832;">,<br /></span><span style="color: #cc7832;"> </span>SerializerProvider serializerProvider<span style="color: #e8ba36;">) </span><span style="color: #cc7832;">throws </span>IOException <span style="color: #54a857;">{<br /></span><span style="color: #54a857;"> </span>jsonGenerator.writeStartObject<span style="color: #e8ba36;">()</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> </span>jsonGenerator.writeStringField<span style="color: #e8ba36;">(</span><span style="color: #9876aa; font-style: italic;">_CLASS</span><span style="color: #cc7832;">, </span>PageImpl.<span style="color: #cc7832;">class</span>.getName<span style="color: #54a857;">()</span><span style="color: #e8ba36;">)</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> </span>jsonGenerator.writePOJOField<span style="color: #e8ba36;">(</span><span style="color: #9876aa; font-style: italic;">CONTENT</span><span style="color: #cc7832;">, </span>value.getContent<span style="color: #54a857;">()</span><span style="color: #e8ba36;">)</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> </span>jsonGenerator.writeNumberField<span style="color: #e8ba36;">(</span><span style="color: #9876aa; font-style: italic;">NUMBER</span><span style="color: #cc7832;">, </span>value.getNumber<span style="color: #54a857;">()</span><span style="color: #e8ba36;">)</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> </span>jsonGenerator.writeNumberField<span style="color: #e8ba36;">(</span><span style="color: #9876aa; font-style: italic;">SIZE</span><span style="color: #cc7832;">, </span>value.getSize<span style="color: #54a857;">()</span><span style="color: #e8ba36;">)</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> </span>jsonGenerator.writeNumberField<span style="color: #e8ba36;">(</span><span style="color: #9876aa; font-style: italic;">TOTAL_ELEMENTS</span><span style="color: #cc7832;">, </span>value.getTotalElements<span style="color: #54a857;">()</span><span style="color: #e8ba36;">)</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> </span>jsonGenerator.writeArrayFieldStart<span style="color: #e8ba36;">(</span><span style="color: #9876aa; font-style: italic;">SORT</span><span style="color: #e8ba36;">)</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> if </span><span style="color: #e8ba36;">(</span>!value.getSort<span style="color: #54a857;">()</span>.isEmpty<span style="color: #54a857;">()</span><span style="color: #e8ba36;">) </span><span style="color: #359ff4;">{<br /></span><span style="color: #359ff4;"> </span><span style="color: #cc7832;">for </span><span style="color: #54a857;">(</span>Sort.Order order : value.getSort<span style="color: #359ff4;">()</span><span style="color: #54a857;">) </span><span style="color: #5060bb;">{<br /></span><span style="color: #5060bb;"> </span>jsonGenerator.writeStartObject<span style="color: #359ff4;">()</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> </span>jsonGenerator.writeStringField<span style="color: #359ff4;">(</span><span style="color: #9876aa; font-style: italic;">PROPERTY</span><span style="color: #cc7832;">, </span>order.getProperty<span style="color: #5060bb;">()</span><span style="color: #359ff4;">)</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> </span>jsonGenerator.writeStringField<span style="color: #359ff4;">(</span><span style="color: #9876aa; font-style: italic;">DIRECTION</span><span style="color: #cc7832;">, </span>order.getDirection<span style="color: #5060bb;">()</span>.name<span style="color: #5060bb;">()</span><span style="color: #359ff4;">)</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> </span>jsonGenerator.writeBooleanField<span style="color: #359ff4;">(</span><span style="color: #9876aa; font-style: italic;">IGNORE_CASE</span><span style="color: #cc7832;">, </span>order.isIgnoreCase<span style="color: #5060bb;">()</span><span style="color: #359ff4;">)</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> </span>jsonGenerator.writeStringField<span style="color: #359ff4;">(</span><span style="color: #9876aa; font-style: italic;">NULL_HANDLING</span><span style="color: #cc7832;">, </span>order.getNullHandling<span style="color: #5060bb;">()</span>.name<span style="color: #5060bb;">()</span><span style="color: #359ff4;">)</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> </span>jsonGenerator.writeEndObject<span style="color: #359ff4;">()</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> </span><span style="color: #5060bb;">}<br /></span><span style="color: #5060bb;"> </span><span style="color: #359ff4;">}<br /></span><span style="color: #359ff4;"> </span>jsonGenerator.writeEndArray<span style="color: #e8ba36;">()</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> </span>jsonGenerator.writeEndObject<span style="color: #e8ba36;">()</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> </span><span style="color: #54a857;">}<br /></span><span style="color: #54a857;"><br /></span><span style="color: #54a857;"> </span><span style="color: #bbb529;">@Override<br /></span><span style="color: #bbb529;"> </span><span style="color: #cc7832;">public void </span><span style="color: #ffc66d;">serializeWithType</span><span style="color: #e8ba36;">(<br /></span><span style="color: #e8ba36;"> </span>PageImpl value<span style="color: #cc7832;">,<br /></span><span style="color: #cc7832;"> </span>JsonGenerator jsonGenerator<span style="color: #cc7832;">,<br /></span><span style="color: #cc7832;"> </span>SerializerProvider serializerProvider<span style="color: #cc7832;">,<br /></span><span style="color: #cc7832;"> </span>TypeSerializer typeSer<span style="color: #e8ba36;">) </span><span style="color: #cc7832;">throws </span>IOException <span style="color: #54a857;">{<br /></span><span style="color: #54a857;"> </span>serialize<span style="color: #e8ba36;">(</span>value<span style="color: #cc7832;">, </span>jsonGenerator<span style="color: #cc7832;">, </span>serializerProvider<span style="color: #e8ba36;">)</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> </span><span style="color: #54a857;">}<br /></span><span style="color: #e8ba36;">}<br /></span></pre><p>3. Define a Deserializer.</p><pre style="padding: 5px; background-color: #2b2b2b; color: #a9b7c6; font-family: "Fira Code", monospace, courier;"><span style="color: #cc7832;">import </span>com.fasterxml.jackson.core.JsonParser<span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;">import </span>com.fasterxml.jackson.databind.DeserializationContext<span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;">import </span>com.fasterxml.jackson.databind.JsonNode<span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;">import </span>com.fasterxml.jackson.databind.deser.std.StdDeserializer<span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;">import </span>com.fasterxml.jackson.databind.jsontype.TypeDeserializer<span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;">import </span>com.fasterxml.jackson.databind.node.ArrayNode<span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;">import </span>org.springframework.data.domain.PageImpl<span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;">import </span>org.springframework.data.domain.PageRequest<span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;">import </span>org.springframework.data.domain.Sort<span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"><br /></span><span style="color: #cc7832;">import </span>java.io.IOException<span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;">import </span>java.util.ArrayList<span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;">import </span>java.util.List<span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"><br /></span><span style="color: #bbb529;">@SuppressWarnings</span><span style="color: #e8ba36;">(</span><span style="color: #6a8759;">"unchecked"</span><span style="color: #e8ba36;">)<br /></span><span style="color: #cc7832;">public class </span>JPADataPageDeserializer
<span style="color: #cc7832;">extends </span>StdDeserializer<span style="color: #e8ba36;"><</span>PageImpl<span style="color: #e8ba36;">>
</span><span style="color: #cc7832;">implements </span>IJPADataPage <span style="color: #e8ba36;">{<br /></span><span style="color: #e8ba36;"> </span><span style="color: #cc7832;">public </span><span style="color: #ffc66d;">JPADataPageDeserializer</span><span style="color: #e8ba36;">(</span>Class<span style="color: #e8ba36;"><</span>?<span style="color: #e8ba36;">> </span>type<span style="color: #e8ba36;">) </span><span style="color: #54a857;">{<br /></span><span style="color: #54a857;"> </span><span style="color: #cc7832;">super</span><span style="color: #e8ba36;">(</span>type<span style="color: #e8ba36;">)</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> </span><span style="color: #54a857;">}<br /></span><span style="color: #54a857;"><br /></span><span style="color: #54a857;"> </span><span style="color: #cc7832;">public </span><span style="color: #ffc66d;">JPADataPageDeserializer</span><span style="color: #e8ba36;">() </span><span style="color: #54a857;">{<br /></span><span style="color: #54a857;"> </span><span style="color: #cc7832;">this</span><span style="color: #e8ba36;">(</span><span style="color: #cc7832;">null</span><span style="color: #e8ba36;">)</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> </span><span style="color: #54a857;">}<br /></span><span style="color: #54a857;"><br /></span><span style="color: #54a857;"> </span><span style="color: #bbb529;">@Override<br /></span><span style="color: #bbb529;"> </span><span style="color: #cc7832;">public </span>PageImpl <span style="color: #ffc66d;">deserialize</span><span style="color: #e8ba36;">(<br /></span><span style="color: #e8ba36;"> </span>JsonParser jsonParser<span style="color: #cc7832;">,<br /></span><span style="color: #cc7832;"> </span>DeserializationContext deserializationContext<span style="color: #e8ba36;">) </span><span style="color: #cc7832;">throws </span>IOException <span style="color: #54a857;">{<br /></span><span style="color: #54a857;"> </span>JsonNode jsonNode = jsonParser.getCodec<span style="color: #e8ba36;">()</span>.readTree<span style="color: #e8ba36;">(</span>jsonParser<span style="color: #e8ba36;">)</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> </span>List<span style="color: #e8ba36;"><</span>?<span style="color: #e8ba36;">> </span>content = deserializationContext.readTreeAsValue<span style="color: #e8ba36;">(</span>jsonNode.get<span style="color: #54a857;">(</span><span style="color: #9876aa; font-style: italic;">CONTENT</span><span style="color: #54a857;">)</span><span style="color: #cc7832;">, </span>List.<span style="color: #cc7832;">class</span><span style="color: #e8ba36;">)</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> int </span>number = jsonNode.get<span style="color: #e8ba36;">(</span><span style="color: #9876aa; font-style: italic;">NUMBER</span><span style="color: #e8ba36;">)</span>.asInt<span style="color: #e8ba36;">(</span><span style="color: #6897bb;">0</span><span style="color: #e8ba36;">)</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> int </span>size = jsonNode.get<span style="color: #e8ba36;">(</span><span style="color: #9876aa; font-style: italic;">SIZE</span><span style="color: #e8ba36;">)</span>.asInt<span style="color: #e8ba36;">(</span><span style="color: #6897bb;">1</span><span style="color: #e8ba36;">)</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> int </span>totalElements = jsonNode.get<span style="color: #e8ba36;">(</span><span style="color: #9876aa; font-style: italic;">TOTAL_ELEMENTS</span><span style="color: #e8ba36;">)</span>.asInt<span style="color: #e8ba36;">(</span><span style="color: #6897bb;">0</span><span style="color: #e8ba36;">)</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> </span>List<span style="color: #e8ba36;"><</span>Sort.Order<span style="color: #e8ba36;">> </span>orders = <span style="color: #cc7832;">new </span>ArrayList<span style="color: #e8ba36;"><>()</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> </span>ArrayNode arrayNode = <span style="color: #e8ba36;">(</span>ArrayNode<span style="color: #e8ba36;">) </span>jsonNode.get<span style="color: #54a857;">(</span><span style="color: #9876aa; font-style: italic;">SORT</span><span style="color: #54a857;">)</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> if </span><span style="color: #e8ba36;">(</span>!arrayNode.isEmpty<span style="color: #54a857;">()</span><span style="color: #e8ba36;">) </span><span style="color: #359ff4;">{<br /></span><span style="color: #359ff4;"> </span><span style="color: #cc7832;">for </span><span style="color: #54a857;">(</span>JsonNode jsonNodeOrder : arrayNode<span style="color: #54a857;">) </span><span style="color: #5060bb;">{<br /></span><span style="color: #5060bb;"> </span>String property = jsonNodeOrder.get<span style="color: #359ff4;">(</span><span style="color: #9876aa; font-style: italic;">PROPERTY</span><span style="color: #359ff4;">)</span>.asText<span style="color: #359ff4;">()</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> </span>Sort.Direction direction = Sort.Direction.<span style="font-style: italic;">valueOf</span><span style="color: #359ff4;">(</span>jsonNodeOrder.get<span style="color: #5060bb;">(</span><span style="color: #9876aa; font-style: italic;">DIRECTION</span><span style="color: #5060bb;">)</span>.asText<span style="color: #5060bb;">()</span><span style="color: #359ff4;">)</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> boolean </span>ignoreCase = jsonNodeOrder.get<span style="color: #359ff4;">(</span><span style="color: #9876aa; font-style: italic;">IGNORE_CASE</span><span style="color: #359ff4;">)</span>.asBoolean<span style="color: #359ff4;">()</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> </span>Sort.NullHandling nullHandling = Sort.NullHandling.<span style="font-style: italic;">valueOf</span><span style="color: #359ff4;">(</span>jsonNodeOrder.get<span style="color: #5060bb;">(</span><span style="color: #9876aa; font-style: italic;">NULL_HANDLING</span><span style="color: #5060bb;">)</span>.asText<span style="color: #5060bb;">()</span><span style="color: #359ff4;">)</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> </span>Sort.Order order = <span style="color: #cc7832;">new </span>Sort.Order<span style="color: #359ff4;">(</span>direction<span style="color: #cc7832;">, </span>property<span style="color: #cc7832;">, </span>nullHandling<span style="color: #359ff4;">)</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> if </span><span style="color: #359ff4;">(</span>ignoreCase<span style="color: #359ff4;">) </span><span style="color: #179387;">{<br /></span><span style="color: #179387;"> </span>order = order.ignoreCase<span style="color: #5060bb;">()</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> </span><span style="color: #179387;">}<br /></span><span style="color: #179387;"> </span>orders.add<span style="color: #359ff4;">(</span>order<span style="color: #359ff4;">)</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> </span><span style="color: #5060bb;">}<br /></span><span style="color: #5060bb;"> </span><span style="color: #359ff4;">}<br /></span><span style="color: #359ff4;"> </span>PageRequest pageRequest = PageRequest.<span style="font-style: italic;">of</span><span style="color: #e8ba36;">(</span>number<span style="color: #cc7832;">, </span>size<span style="color: #cc7832;">, </span>Sort.<span style="font-style: italic;">by</span><span style="color: #54a857;">(</span>orders<span style="color: #54a857;">)</span><span style="color: #e8ba36;">)</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> return new </span>PageImpl<span style="color: #e8ba36;">(</span>content<span style="color: #cc7832;">, </span>pageRequest<span style="color: #cc7832;">, </span>totalElements<span style="color: #e8ba36;">)</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> </span><span style="color: #54a857;">}<br /></span><span style="color: #54a857;"><br /></span><span style="color: #54a857;"> </span><span style="color: #bbb529;">@Override<br /></span><span style="color: #bbb529;"> </span><span style="color: #cc7832;">public </span>Object <span style="color: #ffc66d;">deserializeWithType</span><span style="color: #e8ba36;">(<br /></span><span style="color: #e8ba36;"> </span>JsonParser jsonParser<span style="color: #cc7832;">,<br /></span><span style="color: #cc7832;"> </span>DeserializationContext deserializationContext<span style="color: #cc7832;">,<br /></span><span style="color: #cc7832;"> </span>TypeDeserializer typeDeserializer<span style="color: #e8ba36;">) </span><span style="color: #cc7832;">throws </span>IOException <span style="color: #54a857;">{<br /></span><span style="color: #54a857;"> </span><span style="color: #cc7832;">return </span>deserialize<span style="color: #e8ba36;">(</span>jsonParser<span style="color: #cc7832;">, </span>deserializationContext<span style="color: #e8ba36;">)</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> </span><span style="color: #54a857;">}<br /></span><span style="color: #e8ba36;">}<br /></span></pre><p>4. Define a module.</p><pre style="padding: 5px; background-color: #2b2b2b; color: #a9b7c6; font-family: "Fira Code", monospace, courier;"><span style="color: #cc7832;">import </span>com.fasterxml.jackson.core.Version<span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;">import </span>com.fasterxml.jackson.databind.module.SimpleModule<span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;">import </span>org.springframework.data.domain.PageImpl<span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"><br /></span><span style="color: #cc7832;">public class </span>JPADataModule <span style="color: #cc7832;">extends </span>SimpleModule <span style="color: #e8ba36;">{<br /></span><span style="color: #e8ba36;"> </span><span style="color: #cc7832;">public static final </span>String <span style="color: #9876aa; font-style: italic;">NAME </span>= <span style="color: #6a8759;">"JPA Data Module"</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> public static final </span>Version <span style="color: #9876aa; font-style: italic;">VERSION </span>= <span style="color: #cc7832;">new </span>Version<span style="color: #e8ba36;">(</span><span style="color: #6897bb;">0</span><span style="color: #cc7832;">, </span><span style="color: #6897bb;">1</span><span style="color: #cc7832;">, </span><span style="color: #6897bb;">0</span><span style="color: #cc7832;">, null, null, null</span><span style="color: #e8ba36;">)</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"><br /></span><span style="color: #cc7832;"> public </span><span style="color: #ffc66d;">JPADataModule</span><span style="color: #e8ba36;">() </span><span style="color: #54a857;">{<br /></span><span style="color: #54a857;"> </span><span style="color: #cc7832;">super</span><span style="color: #e8ba36;">(</span><span style="color: #9876aa; font-style: italic;">NAME</span><span style="color: #cc7832;">, </span><span style="color: #9876aa; font-style: italic;">VERSION</span><span style="color: #e8ba36;">)</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> </span>addSerializer<span style="color: #e8ba36;">(</span>PageImpl.<span style="color: #cc7832;">class, new </span>JPADataPageSerializer<span style="color: #54a857;">()</span><span style="color: #e8ba36;">)</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> </span>addDeserializer<span style="color: #e8ba36;">(</span>PageImpl.<span style="color: #cc7832;">class, new </span>JPADataPageDeserializer<span style="color: #54a857;">()</span><span style="color: #e8ba36;">)</span><span style="color: #cc7832;">;<br /></span><span style="color: #cc7832;"> </span><span style="color: #54a857;">}<br /></span><span style="color: #e8ba36;">}<br /></span></pre><p>5. Register the module.</p><pre style="padding: 5px; background-color: #2b2b2b; color: #a9b7c6; font-family: "Fira Code", monospace, courier;">objectMapper.registerModule<span style="color: #e8ba36;">(</span><span style="color: #cc7832;">new </span>JPADataModule<span style="color: #54a857;">()</span><span style="color: #e8ba36;">)</span><span style="color: #cc7832;">;</span></pre><p>Now Jackson is able to handle <span style="color: #2b00fe; font-family: courier;">PageImpl</span> and the Redis cache works.</p>Sam Caohttp://www.blogger.com/profile/03721092279920165184noreply@blogger.com0tag:blogger.com,1999:blog-6602054414215683748.post-75038683871136786672022-04-30T12:20:00.001+08:002022-04-30T12:20:20.272+08:00IDEA / HandBrake / WSL Port Conflict<p>Recently I upgraded HandBrake to the latest version, however, it stopped working. The root cause is TCP port conflict. As usual, I ran <span style="color: #2b00fe; font-family: courier;">net stop winnat && net start winnat</span> and it worked. But, that broke WSL network.</p><p>I didn't want to reset the winnat every time I started Windows with a broken WSL. Finally, I found the root cause: Hyper-V reserves huge amount of TCP ports after Windows is up. The fix is to tell Hyper-V to avoid those commonly used TCP ports.</p><p>The following command can show you the excluded TCP port ranges.</p><p></p><pre style="background-color: #eeeeee; color: #2b00fe; font-family: courier;">> netsh int ipv4 show excludedportrange protocol=tcp
Protocol tcp Port Exclusion Ranges
Start Port End Port
---------- --------
80 80
1000 1010
1020 1030
......
</pre><p></p><p>As you can see, huge amount of TCP ports are reserved by Hyper-V. So, let's tell Hyper-V not to be that greedy by executing the following command.</p><pre style="background-color: #eeeeee; color: #2b00fe; font-family: courier;">> netsh int ipv4 set dynamic tcp start=49152 num=16384
</pre><p>That command tells Windows to allow dynamic TCP ports from 49152 so that Hyper-V is only able to reserve TCP ports starting from 49152. The following command can verify the setting is correct.</p><pre style="background-color: #eeeeee; color: #2b00fe; font-family: courier;">> netsh int ipv4 show dynamic protocol=tcp
Protocol tcp Dynamic Port Range
---------------------------------
Start Port : 49152
Number of Ports : 16384
</pre><p>Once the new dynamic TCP port range is set, just reboot your machine and everything goes back to normal. IDEA can start smoothly, WSL network is always on, HandBrake works all the time.</p>Sam Caohttp://www.blogger.com/profile/03721092279920165184noreply@blogger.com0tag:blogger.com,1999:blog-6602054414215683748.post-25987238406602884672022-01-11T10:19:00.000+08:002022-01-11T10:19:05.418+08:00dlopen failed: cannot locate symbol "__aarch64_ldadd4_relax"<p>In Android development, it's rare to meet the following error.</p><p><span style="color: #cc0000; font-family: courier;">dlopen failed: cannot locate symbol "__aarch64_ldadd4_relax"</span></p><p><span style="font-family: inherit;">I searched the whole internet for a solution, but couldn't get a practical one. Actually, the root cause is simple: The Android NDK is too old.</span></p><p><span style="font-family: inherit;">The solution in my case is:</span></p><p></p><ol style="text-align: left;"><li>Upgrade CMake to the latest version.</li><li>Upgrade Android NDK to the latest version.</li></ol><p></p>Sam Caohttp://www.blogger.com/profile/03721092279920165184noreply@blogger.com0tag:blogger.com,1999:blog-6602054414215683748.post-85246704514129275522021-11-03T14:31:00.003+08:002021-11-03T14:31:46.810+08:00Javet Supports Android ABI >= 21<p> Starting from v1.0.3, Javet supports Android ABI >= 21. Enjoy!</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjKMNb9r3fMFjPicd3lRxS_2kGm9JQkTHJL63gmgGEMIAqBEkjCHru4kkqD9vj-QthaTQ5x5kSyGinrmT9yBOLfNORQ2IT7NA4K_v0rAA_1p-LMDRLbB3-uWrww6wdTe32qH1V-6purcoV3ThieUxA72VK8PZKieCAFsXtSEmfzBHGc1lfz7MGhkfcs=s1136" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1136" data-original-width="562" height="640" src="https://blogger.googleusercontent.com/img/a/AVvXsEjKMNb9r3fMFjPicd3lRxS_2kGm9JQkTHJL63gmgGEMIAqBEkjCHru4kkqD9vj-QthaTQ5x5kSyGinrmT9yBOLfNORQ2IT7NA4K_v0rAA_1p-LMDRLbB3-uWrww6wdTe32qH1V-6purcoV3ThieUxA72VK8PZKieCAFsXtSEmfzBHGc1lfz7MGhkfcs=w316-h640" width="316" /></a></div><br /><p><br /></p>Sam Caohttp://www.blogger.com/profile/03721092279920165184noreply@blogger.com0tag:blogger.com,1999:blog-6602054414215683748.post-177768460153227752021-10-25T17:00:00.002+08:002021-10-25T17:00:29.438+08:00Javet for Android is Released<p><a href="https://github.com/caoccao/Javet/" style="background-color: white; color: #2288bb; font-family: "Trebuchet MS", Trebuchet, Verdana, sans-serif; font-size: 13.2px; text-decoration-line: none;">Javet</a><span style="background-color: white; color: #666666; font-family: "Trebuchet MS", Trebuchet, Verdana, sans-serif; font-size: 13.2px;"> is Java + V8 (JAVa + V + EighT). It is an awesome way of embedding Node.js and V8 in Java.</span></p><p><span style="background-color: white; color: #666666; font-family: "Trebuchet MS", Trebuchet, Verdana, sans-serif; font-size: 13.2px;">It's been more than half a year for the Javet users to wait for the Android support. Now, Javet has officially supported Android.</span></p><p><span style="background-color: white; color: #666666; font-family: "Trebuchet MS", Trebuchet, Verdana, sans-serif; font-size: 13.2px;">The API and coding experience are identical to the ones on Linux, Mac OS and Windows.</span></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgTz5qTRqja6TIPrtlKFD0uDuLT9TKBq7Gigi7B9K0JxFwUr1d4luXVFQLG6uhZ6N1trjdr2-nMAC84wy9JadwYM0Fkrxk5YK5MQojgcOI4jn8Ed1dgfa08ue76PU5KffCHuIIPhr6fEe6Y0GJazRkYO-64hR8a293o-yD_lYFTlu2O8xrl_Cb9ZbT3=s1710" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="729" data-original-width="1710" height="170" src="https://blogger.googleusercontent.com/img/a/AVvXsEgTz5qTRqja6TIPrtlKFD0uDuLT9TKBq7Gigi7B9K0JxFwUr1d4luXVFQLG6uhZ6N1trjdr2-nMAC84wy9JadwYM0Fkrxk5YK5MQojgcOI4jn8Ed1dgfa08ue76PU5KffCHuIIPhr6fEe6Y0GJazRkYO-64hR8a293o-yD_lYFTlu2O8xrl_Cb9ZbT3=w400-h170" width="400" /></a></div><span style="background-color: white; color: #666666; font-family: "Trebuchet MS", Trebuchet, Verdana, sans-serif; font-size: 13.2px;"><br /></span><p></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjL8HyE9PS8OzBi0AYOKMQaJcWOs0eC52zgIrQo_XBtNEOJ_M0ryyPU1ycQH4c8rgOtDEA-zinjBtXhuNuNuq4ge_WbbuCg43EMS7jDJ7lPkB9rm6ykpv2motjzlaucOh1F7E7pTzcShBwANmyO2FU8RdnKvtQ3jt7mIzKOjtdcZkVOvGZ4QftiqlUY=s379" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="302" data-original-width="379" height="319" src="https://blogger.googleusercontent.com/img/a/AVvXsEjL8HyE9PS8OzBi0AYOKMQaJcWOs0eC52zgIrQo_XBtNEOJ_M0ryyPU1ycQH4c8rgOtDEA-zinjBtXhuNuNuq4ge_WbbuCg43EMS7jDJ7lPkB9rm6ykpv2motjzlaucOh1F7E7pTzcShBwANmyO2FU8RdnKvtQ3jt7mIzKOjtdcZkVOvGZ4QftiqlUY=w400-h319" width="400" /></a></div><br /><span style="background-color: white; color: #666666; font-family: "Trebuchet MS", Trebuchet, Verdana, sans-serif; font-size: 13.2px;"><br /></span><p></p>Sam Caohttp://www.blogger.com/profile/03721092279920165184noreply@blogger.com0tag:blogger.com,1999:blog-6602054414215683748.post-78820436191648931002021-10-22T15:39:00.006+08:002021-10-22T15:40:15.429+08:00Javet for Android is on the Way<p><a href="https://github.com/caoccao/Javet/">Javet</a> is Java + V8 (JAVa + V + EighT). It is an awesome way of embedding Node.js and V8 in Java.</p><p>It's been a long while for many Javet users to wait for the Android support. Now, it is coming true as the first Android build is being tested. If you are interested, please join us at <a href="https://discord.gg/R4vvKU96gw">discord</a>.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhBZJZycOO801Sv62rzNncUF5pyq3GPgQ8mn6popfXIvLJk2pfuJa8-bjoVMPfllKqOkWT_Iue7pghj9Wy48VPn5Qo48q-ViY_T3ib6xWxS7xco4Q5zKEeWRo38QXMGd_nwaHOL49kecpPrCqFVYb13tT2CeKZ4ih3qV1OgYvRSdUjm1JDx8yI14grX=s1710" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="729" data-original-width="1710" height="272" src="https://blogger.googleusercontent.com/img/a/AVvXsEhBZJZycOO801Sv62rzNncUF5pyq3GPgQ8mn6popfXIvLJk2pfuJa8-bjoVMPfllKqOkWT_Iue7pghj9Wy48VPn5Qo48q-ViY_T3ib6xWxS7xco4Q5zKEeWRo38QXMGd_nwaHOL49kecpPrCqFVYb13tT2CeKZ4ih3qV1OgYvRSdUjm1JDx8yI14grX=w640-h272" width="640" /></a></div><br /><p><br /></p>Sam Caohttp://www.blogger.com/profile/03721092279920165184noreply@blogger.com0tag:blogger.com,1999:blog-6602054414215683748.post-89784326501263683852021-09-10T23:16:00.004+08:002021-09-13T21:17:59.260+08:00MacBook Air mid-2012 from Lion to CatalinaI had been asked by potential <a href="https://github.com/caoccao/Javet">Javet</a> users for Mac OS release for many moths before the first Mac OS release was published. I have to admit I have no plan to purchase Mac OS devices in the new future for financial reason.<div><br /></div><div>Luckily, I have a MacBook Air mid-2012 resting in the dust. I revived it and would like to upgrade it to the latest Mac OS.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLsIDBfUPzfujVFWQqlTYvGx7QtAcN0jR4txfrDNY-nNuhy8C7uhK0mX04J-4pebLEqX4ogNxgp94l8t_mepkFvzDERo2szDU5axl4WRUZ6iZ35Sqm_wrJF3yUv09XVxPkUCPgDTr-Q4Q/s2048/Lion.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1538" data-original-width="2048" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLsIDBfUPzfujVFWQqlTYvGx7QtAcN0jR4txfrDNY-nNuhy8C7uhK0mX04J-4pebLEqX4ogNxgp94l8t_mepkFvzDERo2szDU5axl4WRUZ6iZ35Sqm_wrJF3yUv09XVxPkUCPgDTr-Q4Q/w400-h300/Lion.jpg" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div>The problem was I had to upgrade it to Lion, then to El Capitan, Mojave, eventually to Catalina which is the last version supported by MacBook Air mid-2012.</div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjv9ukj8rPpmQqdfYnhv3nM33HjORiHHhc-z_DKDHgLv2gFG_CJAQOQQDmqU332zpqyddsSlrE0aBMmt7V1H0zybBHtBMmga97L8l9rBHh7TeBAw3ZnlYYuJfI5PFc9OIHHkLAriZM15LM/s2048/Mojave.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1538" data-original-width="2048" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjv9ukj8rPpmQqdfYnhv3nM33HjORiHHhc-z_DKDHgLv2gFG_CJAQOQQDmqU332zpqyddsSlrE0aBMmt7V1H0zybBHtBMmga97L8l9rBHh7TeBAw3ZnlYYuJfI5PFc9OIHHkLAriZM15LM/w400-h300/Mojave.jpg" width="400" /></a></div><br /><div>It took ~8 hours to get there. Then, I installed xcode and related tools. Luckily, it met the lowest requirement for building V8 v9.2.</div><div><br /></div><div>Obviously, MacBook Air mid-2012 is tooooo slow in building modern applications. It took ~4 hours to build V8, and another ~4 hours to build Node.js. The result was good as Javet for Mac OS x86_64 was built successfully.</div><div><br /></div><div>However, MacBook Air mid-2012 will soon been retired by a new release of V8. When that day comes, I will no longer release Mac OS x86_64 version unless I get enough donation for me to purchase a new device.</div>Sam Caohttp://www.blogger.com/profile/03721092279920165184noreply@blogger.com0tag:blogger.com,1999:blog-6602054414215683748.post-50234364107191854732021-09-10T10:36:00.000+08:002021-09-10T10:36:15.066+08:00Migrate from J2V8 to Javet<p>How to migrate from J2V8 to <a href="https://github.com/caoccao/Javet">Javet</a> is a frequently asked question,
especially when people are evaluating Javet. I created Javet in Jan,
2021 for various reasons (<a class="reference internal" href="https://www.caoccao.com/Javet/faq/background/what_is_the_motivation.html"><span class="doc">What is the Motivation?</span></a>, <a class="reference internal" href="https://www.caoccao.com/Javet/faq/background/history_with_j2v8.html"><span class="doc">History with J2V8</span></a>).
After the first release v0.7.0 was published, I started migrating from
J2V8 to Javet. It was quite smooth, though it took a week.</p>
<div class="section" id="why-migrate-from-j2v8-to-javet">
<h2>Why Migrate from J2V8 to Javet?<a class="headerlink" href="https://www.caoccao.com/Javet/tutorial/migration_guides/migrate_from_j2v8.html#why-migrate-from-j2v8-to-javet" title="Permalink to this headline"></a></h2>
<ul class="simple">
<li><p>Its Linux, Mac OS and Windows releases have been abandoned for years.</p></li>
<li><p>Its type hierarchy is inconsistent because primitive types are out of the hierarchy so that tedious <code class="docutils literal notranslate">if-else</code> sentences have to be repeated all over the code base.</p></li>
<li><p>Its function registration API is kind of verbose.</p></li>
<li><p>Segfaults take place so frequently and don't get maintainers' attention for years.</p></li>
<li><p>Its locking mechanism heavily increases mental pressure in the code base.</p></li>
<li><p>Its V8 runtime is not multi-threaded friendly unless application adds a synchronous layer on top of it.</p></li>
</ul>
</div>
<div class="section" id="migration-guides">
<h2>Migration Guides<a class="headerlink" href="https://www.caoccao.com/Javet/tutorial/migration_guides/migrate_from_j2v8.html#migration-guides" title="Permalink to this headline"></a></h2>
<div class="section" id="v8-v8runtime">
<h3>V8 ⟶ V8Runtime<a class="headerlink" href="https://www.caoccao.com/Javet/tutorial/migration_guides/migrate_from_j2v8.html#v8-v8runtime" title="Permalink to this headline"></a></h3>
<ul class="simple">
<li><p><code class="docutils literal notranslate">V8</code> in J2V8 is <code class="docutils literal notranslate">V8Runtime</code> in Javet.</p></li>
<li><p><code class="docutils literal notranslate">V8</code> in J2V8 carries 2 roles: 1 as the V8 runtime and 1 as the global object (<code class="docutils literal notranslate">globalThis</code> or <code class="docutils literal notranslate">global</code>). In Javet, <code class="docutils literal notranslate">V8Runtime</code> no longer inherits from <code class="docutils literal notranslate">V8Value</code> so that it literally represents the V8 runtime. <code class="docutils literal notranslate">V8Runtime.getGlobalObject()</code> is dedicated to the global object.</p></li>
<li><p><code class="docutils literal notranslate">V8Runtime</code> has much richer API than <code class="docutils literal notranslate">V8</code> has. E.g. <code class="docutils literal notranslate">compileV8Module()</code>, <code class="docutils literal notranslate">lowMemoryNotification()</code>, <code class="docutils literal notranslate">terminateExecution()</code>.</p></li>
</ul>
</div>
<div class="section" id="primitive-types">
<h3>Primitive Types<a class="headerlink" href="https://www.caoccao.com/Javet/tutorial/migration_guides/migrate_from_j2v8.html#primitive-types" title="Permalink to this headline"></a></h3>
<ul class="simple">
<li><p>Primitive types in Javet inherit from <code class="docutils literal notranslate">V8ValuePrimitive</code> ⟶ <code class="docutils literal notranslate">V8Value</code> ⟶ <code class="docutils literal notranslate">V8Data</code>.</p></li>
<li><p>The Javet type hierarchy is consistent so that <code class="docutils literal notranslate">V8Value</code> in all supported API can represent all V8 types. This is hard in J2V8 because <code class="docutils literal notranslate">Object</code> has to be used to represent all types, however, by using <code class="docutils literal notranslate">Object</code> the type check during compilation doesn't work at all and that is a rich source of runtime bugs or even segfaults.</p></li>
</ul>
</div>
<div class="section" id="registerjavamethod-v8function">
<h3>registerJavaMethod() ⟶ @V8Function<a class="headerlink" href="https://www.caoccao.com/Javet/tutorial/migration_guides/migrate_from_j2v8.html#registerjavamethod-v8function" title="Permalink to this headline"></a></h3>
<ul class="simple">
<li><p>It is quite painful to register many functions in J2V8. Javet
makes that a declarative one instead of the imperative one. Just
decorate the target function with <code class="docutils literal notranslate">@V8Function</code>, then call <code class="docutils literal notranslate">V8ValueObject.bind(javaObject)</code> to bind that Java object, it's done.</p></li>
<li><p>In addition, Javet provides <code class="docutils literal notranslate">@V8Property</code> which allows registering getters and setters in the same manner. That feature has never been delivered by J2V8.</p></li>
<li><p>Javet also allows unbinding the registration. Just call <code class="docutils literal notranslate">V8ValueObject.unbind(javaObject)</code>.</p></li>
</ul>
<p>Please refer to <a class="reference internal" href="https://www.caoccao.com/Javet/reference/v8_function.html"><span class="doc">V8 Function</span></a> for more details.</p>
</div>
<div class="section" id="v8locker">
<h3>V8Locker<a class="headerlink" href="https://www.caoccao.com/Javet/tutorial/migration_guides/migrate_from_j2v8.html#v8locker" title="Permalink to this headline"></a></h3>
<ul class="simple">
<li><p>Javet introduced <strong>Implicit Mode</strong> which allows applications to eliminate <code class="docutils literal notranslate">V8Locker</code> from the code base and still be able to share the same <code class="docutils literal notranslate">V8Runtime</code>
among multiple threads, because Javet does the synchronization
automatically. That frees applications developers from the tedious <code class="docutils literal notranslate">acquire()</code> and <code class="docutils literal notranslate">release()</code> calls, and gets the rid of the runtime exceptions caused by multiple threads.</p></li>
<li><p>Javet also has <strong>Explicit Mode</strong> for performance sensitive scenarios.</p></li>
</ul>
<p>Please refer to <a class="reference internal" href="https://www.caoccao.com/Javet/reference/lock.html"><span class="doc">Know the Lock</span></a> for more details.</p>
</div>
<div class="section" id="type-conversion">
<h3>Type Conversion<a class="headerlink" href="https://www.caoccao.com/Javet/tutorial/migration_guides/migrate_from_j2v8.html#type-conversion" title="Permalink to this headline"></a></h3>
<ul class="simple">
<li><p>Javet has built-in <code class="docutils literal notranslate">JavetObjectConverter</code>
which covers the majority cases on type conversion so that the
arguments of Javet API can be of any type and the converter just does
the conversion transparently. That frees application developers from
writing tedious type conversion code everywhere.</p></li>
<li><p>Javet also provides <code class="docutils literal notranslate">JavetProxyConverter</code>
which allows injecting arbitrary Java objects in V8 and polyfilling
Java interfaces with JavaScript functions or objects. Especially the
polyfilling feature implies hotfixing business logic without restarting
the JVM.</p></li>
</ul>
<p>Please refer to <a class="reference internal" href="https://www.caoccao.com/Javet/tutorial/advanced/object_converter.html"><span class="doc">Object Converter</span></a> for more details.</p>
</div>
<div class="section" id="node-js-and-v8">
<h3>Node.js and V8<a class="headerlink" href="https://www.caoccao.com/Javet/tutorial/migration_guides/migrate_from_j2v8.html#node-js-and-v8" title="Permalink to this headline"></a></h3>
<ul class="simple">
<li><p>Javet provides both Node.js mode and V8 mode for various usages.
Each mode stays at a dedicated classloader so that both modes don't
cross each other, and are completely isolated. If the application only
uses one mode, it doesn't need to pay extra amount of memory for the
other mode because the other mode is not loaded at all. Of course, both
modes can be unloaded as well without shutting down the JVM.</p></li>
<li><p>In Node.js mode, all node modules can be directly used including the native modules. Please refer to <a class="reference internal" href="https://www.caoccao.com/Javet/reference/modularization.html"><span class="doc">Modularization</span></a> for more detail.</p></li>
<li><p>In V8 mode, it is much more secure than the Node.js mode is, but lacks of some basic ES API, e.g. <code class="docutils literal notranslate">setTimeout()</code>. Project <a class="reference external" href="https://github.com/caoccao/Javenode">Javenode</a> is the one that aims at simulating Node.js with Java in Javet V8 mode.</p></li>
</ul>
<p>Please refer to <a class="reference internal" href="https://www.caoccao.com/Javet/development/design.html"><span class="doc">Javet Design</span></a> for more details.</p>
</div>
<div class="section" id="es6-module">
<h3>ES6 Module<a class="headerlink" href="https://www.caoccao.com/Javet/tutorial/migration_guides/migrate_from_j2v8.html#es6-module" title="Permalink to this headline"></a></h3>
<ul class="simple">
<li><p>Javet supports <code class="docutils literal notranslate"><span class="pre">import</span> <span class="pre">{</span> <span class="pre">***</span> <span class="pre">}</span> <span class="pre">from</span> <span class="pre">'***.js'</span></code> and exposes module resolve event for applications to specify where to locate the modules.</p></li>
</ul>
<p>Please refer to <a class="reference internal" href="https://www.caoccao.com/Javet/reference/modularization.html"><span class="doc">Modularization</span></a> for more detail.</p>
</div>
</div>
<div class="section active" id="blessing">
<h2>Blessing<a class="headerlink" href="https://www.caoccao.com/Javet/tutorial/migration_guides/migrate_from_j2v8.html#blessing" title="Permalink to this headline"></a></h2>
<p>In case this migration guide couldn't cover all your use cases, please contact the maintainer at <a class="reference external" href="https://discord.gg/R4vvKU96gw">discord</a>. Wish you a successful migration!</p></div>Sam Caohttp://www.blogger.com/profile/03721092279920165184noreply@blogger.com0tag:blogger.com,1999:blog-6602054414215683748.post-46304801401883032102021-09-06T11:15:00.004+08:002021-09-06T11:15:33.607+08:00Javet v0.9.11 is released with some exciting features<p class="q-text qu-display--block" style="background-color: white; box-sizing: border-box; color: #282829; direction: ltr; font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-size: 15px; margin: 0px 0px 1em; overflow-wrap: anywhere; padding: 0px; word-break: break-word;"><span style="background: none;"><a href="https://github.com/caoccao/Javet" target="_blank">Javet</a> v0.9.11 is released with some exciting features.</span></p><ul class="q-box" style="background-color: white; box-sizing: border-box; color: #282829; direction: ltr; font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; font-size: 15px; list-style-image: initial; list-style-position: initial; margin: 0px 2em 1em 0px; overflow-wrap: break-word; padding: 0px;"><li class="q-relative" style="box-sizing: border-box; margin: 0px 0px 0px 2em; padding: 0px 0px 0.7em; position: relative;"><span style="background: none;">Mac OS (x86_64)</span></li><li class="q-relative" style="box-sizing: border-box; margin: 0px 0px 0px 2em; padding: 0px 0px 0.7em; position: relative;"><span style="background: none;">Node.js v14.17.6</span></li><li class="q-relative" style="box-sizing: border-box; margin: 0px 0px 0px 2em; padding: 0px 0px 0.7em; position: relative;"><span style="background: none;">V8 v9.3.345.16</span></li><li class="q-relative" style="box-sizing: border-box; margin: 0px 0px 0px 2em; padding: 0px 0px 0.7em; position: relative;"><span style="background: none;">Getter/Setter by Symbol</span></li><li class="q-relative" style="box-sizing: border-box; margin: 0px 0px 0px 2em; padding: 0px 0px 0.7em; position: relative;"><span style="background: none;">Dynamic Proxy for Java Objects by JavaScript Objects</span></li><li class="q-relative" style="box-sizing: border-box; margin: 0px 0px 0px 2em; padding: 0px; position: relative;"><span style="background: none;">Promise</span></li></ul>Sam Caohttp://www.blogger.com/profile/03721092279920165184noreply@blogger.com0tag:blogger.com,1999:blog-6602054414215683748.post-77120090794777394612021-09-02T17:42:00.003+08:002021-09-03T10:26:37.564+08:00How to Efficiently Wait for RxJava Observer to Complete?Almost all tutorials including the RxJava official ones deliver a message to RxJava developers that <code style="color: #cc0000;">Thread.sleep(...)</code> is recommended in testing RxJava code snippets. However, that is not efficient enough.<div><br /></div><div>Here is an alternative way for your reference.</div><div><code><pre class="java">AtomicBoolean atomicBoolean = new AtomicBoolean(false);
ExecutorService executorService = Executors.newFixedThreadPool(4);
Observable.timer(10, TimeUnit.MILLISECONDS, Schedulers.from(executorService))
.subscribe(t -> atomicBoolean.set(true));
executorService.awaitTermination(100, TimeUnit.MILLISECONDS);
assertTrue(atomicBoolean.get());
</pre></code></div><div>The key is to inject a custom thread pool and wait for that thread pool to complete.</div>Sam Caohttp://www.blogger.com/profile/03721092279920165184noreply@blogger.com0tag:blogger.com,1999:blog-6602054414215683748.post-6421836532682743992021-09-01T17:43:00.002+08:002021-09-01T17:43:15.669+08:00V8 v9.3 and Mac OS: error: no member named 'forward' in namespace 'std'<p>As Chrome v93 is stable, I began to upgrade Javet to V8 v9.3.345.16. However, the build failed on my MacBook Air with the following error messages.</p><p><code></code></p><pre><code><b>../../include/cppgc/allocation.h:168:39: <span style="color: red;">error</span>: no member named 'forward' in namespace 'std'</b>
<span style="color: #666666;">T* object = ::new (memory) T(std::forward<Args>(args)...);</span>
<span style="color: #6aa84f;">~~~~~^</span>
<b>../../include/cppgc/allocation.h:168:47: <span style="color: red;">error</span>: 'Args' does not refer to a value</b>
<span style="color: #666666;">T* object = ::new (memory) T(std::forward<Args>(args)...);</span>
<span style="color: #6aa84f;">^</span></code></pre><p></p><p>Well, as <span style="color: red;"><a href="https://en.cppreference.com/w/cpp/utility/forward" target="_blank">std::forward</a></span> is missing, the fix is simple. Just add <span style="color: #2b00fe;">#include <utility></span> into <span style="color: #2b00fe;">include/cppgc/allocation.h</span> and it works.</p>Sam Caohttp://www.blogger.com/profile/03721092279920165184noreply@blogger.com0tag:blogger.com,1999:blog-6602054414215683748.post-77544117523618855482021-08-16T17:05:00.003+08:002021-08-16T17:05:59.883+08:00Javet Supports Mac OS Now<p><a href="https://github.com/caoccao/Javet" target="_blank">Javet</a> is Java + V8 (JAVa + V + EighT). It is an awesome way of embedding Node.js and V8 in Java.</p><p>I'm very happy to announce Javet supports Mac OS x86_64 from v0.9.9.</p><p>Maven</p><pre><code class="xml"><dependency>
<groupId>com.caoccao.javet</groupId>
<artifactId>javet-macos</artifactId>
<version>0.9.9</version>
</dependency></code></pre><p></p><p>Gradle Kotlin DSL</p><p><code></code></p><pre><code>implementation("com.caoccao.javet:javet-macos:0.9.9")</code></pre><p></p><p>Gradle Groovy DSL</p><p><code></code></p><pre><code>implementation 'com.caoccao.javet:javet-macos:0.9.9'</code></pre><p>Hello Javet</p><p><code></code></p><pre><code class="javascript">// Node.js Mode
try (V8Runtime v8Runtime = V8Host.getNodeInstance().createV8Runtime()) {
System.out.println(v8Runtime.getExecutor("'Hello Javet'").executeString());
}
// V8 Mode
try (V8Runtime v8Runtime = V8Host.getV8Instance().createV8Runtime()) {
System.out.println(v8Runtime.getExecutor("'Hello Javet'").executeString());
}</code></pre><p></p><p></p>Sam Caohttp://www.blogger.com/profile/03721092279920165184noreply@blogger.com0tag:blogger.com,1999:blog-6602054414215683748.post-43590150094956663792021-08-11T15:26:00.008+08:002021-08-11T15:55:17.242+08:00JNI Symbol Conflicts in Mac OS<h2 style="text-align: left;">Background</h2><div>When I was adding Mac OS support to my open source project <a href="https://github.com/caoccao/Javet/" target="_blank">Javet</a>, I found a weird behavior caused by JNI symbol conflicts which resulted in JVM 8 core-dump.</div><div><br /></div><div>Javet is Java + V8 (JAVa + V + EighT). It is an awesome way of embedding Node.js and V8 in Java. It's embedding behavior relies on 2 JNI libraries one for Node.js and one for V8. Both of them are loaded by dedicated classloader and share the same API and symbols, except that the Node.js one exposes more Node.js flavored symbols.</div><div><br /></div><div>In Javet unit test, it loads both Node.js and V8 libraries and performs complicated test. The test goes well in Linux and Windows, but core-dumps in Mac OS.</div><h2 style="text-align: left;">Analysis</h2><div>The dump file shows the call stack crosses the library boundary.</div><div><code><pre>...node...dylib
...node...dylib
<span style="color: red;">...node...dylib <== Something wrong happens here.</span>
...v8...dylib
...v8...dylib
...v8...dylib</pre></code></div><div>It seems JVM in Mac OS registers global symbols in the same memory space, so that the V8 library calls into Node.js library. Obviously, that for sure leads to core-dump.</div><h2 style="text-align: left;">Failed Attempts</h2><div><ul style="text-align: left;"><li>I tried various distributions of JDK 8. None of them worked. It seems to be the Mac OS' behavior.</li><li>I tried to adjust the <span style="background-color: #cccccc;">CMakeLists.txt</span>. All my attempts failed.</li></ul></div><h2 style="text-align: left;">Fix</h2><div>I kept reviewing the call stack and realized the issue might be gone if these symbols were not global symbols.</div><div><br /></div><div>So I created <span style="background-color: #cccccc; font-family: courier;">jni/exported_symbols_list.txt</span> with the following content.</div><div><code><pre>_JNI_OnLoad
_JNI_OnUnload
_Java_com_caoccao_javet_*
_napi_*</pre></code></div><div>Then, I updated <span style="background-color: #cccccc;">CMakeLists.txt</span> with the following content.</div><div><code><pre>target_link_libraries(Javet PUBLIC -exported_symbols_list ${CMAKE_SOURCE_DIR}/jni/exported_symbols_list.txt)</pre></code></div><div>And, it works, no more core-dump with all test cases pass.</div>Sam Caohttp://www.blogger.com/profile/03721092279920165184noreply@blogger.com0tag:blogger.com,1999:blog-6602054414215683748.post-2916815473913190212021-08-02T14:23:00.001+08:002021-08-09T14:24:26.281+08:00Javet - Java and JavaScript Interop<p><a href="https://github.com/caoccao/Javet/" target="_blank">Javet</a> is Java + V8 (JAVa + V + EighT). It is an awesome way of embedding Node.js and V8 in Java.</p><p>From v0.9.8, Javet allows injecting arbitrary Java objects into V8 which enables the complete interop between Java and JavaScript. To enable this feature, application just needs to call <span style="color: #38761d; font-family: courier;">v8Runtime.setConverter(new JavetProxyConverter());</span>. Here are 3 examples.</p><h2 style="text-align: left;">Inject a Static Class</h2><div><pre class="java"><code>v8Runtime.getGlobalObject().set("System", System.class);
v8Runtime.getExecutor("function main() {\n" +
// Java reference can be directly called in JavaScript.
" System.out.println('Hello from Java');\n" +
// Java reference can be directly assigned to JavaScript variable.
" const println = System.out.println;\n" +
// Java reference can be directly assigned to JavaScript variable.
" println('Hello from JavaScript');\n" +
"}\n" +
"main();").executeVoid();
v8Runtime.getGlobalObject().delete("System");
/*
* Output:
* Hello from Java
* Hello from JavaScript
*/</code></pre></div><h2 style="text-align: left;">Inject an Enum</h2><div><pre class="java"><code>v8Runtime.getGlobalObject().set("Color", Color.class);
System.out.println(v8Runtime.getExecutor("Color.pink.toString();").executeString());
System.out.println("The enum in JavaScript is the one in Java: " +
(Color.pink == (Color) v8Runtime.getExecutor("Color.pink;").executeObject()));
v8Runtime.getGlobalObject().delete("Color");
/*
* Output:
* java.awt.Color[r=255,g=175,b=175]
* The enum in JavaScript is the one in Java: true
*/</code></pre></div><h2 style="text-align: left;">Inject a Pattern</h2><div><pre class="java"><code>Pattern pattern = Pattern.compile("^\\d+$");
v8Runtime.getExecutor("function main(pattern) {\n" +
" return [\n" +
" pattern.matcher('123').matches(),\n" +
" pattern.matcher('abc').matches(),\n" +
" ];\n" +
"}").executeVoid();
System.out.println(v8Runtime.getGlobalObject().invokeObject("main", pattern).toString());
/*
* Output:
* [true, false]
*/</code></pre></div><h2 style="text-align: left;">Inject a StringBuilder</h2><div><pre class="java"><code>v8Runtime.getGlobalObject().set("StringBuilder", StringBuilder.class);
System.out.println(v8Runtime.getExecutor("function main() {\n" +
" return new StringBuilder('Hello').append(' from StringBuilder').toString();\n" +
"}\n" +
"main();").executeString());
v8Runtime.getGlobalObject().delete("StringBuilder");
/*
* Output:
* Hello from StringBuilder
*/</code></pre></div>Sam Caohttp://www.blogger.com/profile/03721092279920165184noreply@blogger.com0tag:blogger.com,1999:blog-6602054414215683748.post-74915780989521185262021-07-29T23:58:00.002+08:002021-07-30T08:43:11.916+08:00Peking Opera Blues: Pure DeliriumEarly today I was watching the newly (in 2020) released extras in a 2-disc BD and was shocked by your 18'25 story with Peking Opera Blues. At the end of it, I found a link to this <a href="http://www.darrenwheeling.com/2012/08/peking-opera-blues-pure-delirium_27.html" target="_blank">blog post</a>. What an amazing thing from watching BD extras.<div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPjgcKa3aEDxkITT_oGDeARSPIrQOjeHxp8rjYeAZ_aNERNkch7FEBXNNQF48fY6ULlEkR6DHRSW3JEovP2v8i5g9zQFX6YIqwcHYeomv-3t4Wd-knHNIvcVisT2EYQ0VTHw4nAjKR0DLV/s750/peking_opera_blues_main_image5.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="636" data-original-width="750" height="339" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPjgcKa3aEDxkITT_oGDeARSPIrQOjeHxp8rjYeAZ_aNERNkch7FEBXNNQF48fY6ULlEkR6DHRSW3JEovP2v8i5g9zQFX6YIqwcHYeomv-3t4Wd-knHNIvcVisT2EYQ0VTHw4nAjKR0DLV/w400-h339/peking_opera_blues_main_image5.jpg" width="400" /></a></div><br /><div><br /></div>Sam Caohttp://www.blogger.com/profile/03721092279920165184noreply@blogger.com0tag:blogger.com,1999:blog-6602054414215683748.post-38625458156292248702021-05-19T13:38:00.005+08:002021-05-20T18:05:29.471+08:00Javet - Patch V8 Function at Source Code Level<p><a href="https://github.com/caoccao/Javet/" target="_blank">Javet</a> is Java + V8 (JAVa + V + EighT). It is an awesome way of embedding Node.js and V8 in Java.</p><p>With the release of v0.8.8, Javet supports patching V8 function at source code level on the fly.</p><h2 style="text-align: left;">Why is That Important?</h2><p>Functions can be changed on the fly at JavaScript code level via Javet API. Why to choose this approach? Because sometimes local scoped context is required which is usually called closure. E.g:</p><pre class="javascript"><code>const a = function () {
const b = 1;
return () => b;
}
const x = a();
console.log(x());
// Output is: 1</code></pre><p>Local const b is visible to the anonymous function at line 3, but invisible to the function interceptor. Javet provides a way of changing the function at JavaScript source code level so that local scoped context is still visible.</p><h2 style="text-align: left;">How?</h2><p>getSourceCode() and setSourceCode(String sourceCode) are designed for getting and setting the source code. setSourceCode(String sourceCode) actually performs the follow steps.</p><pre class="python"><code>def setSourceCode(sourceCode):
existingSourceCode = v8Function.getSourceCode()
(startPosition, endPosition) = v8Function.getPosition()
newSourceCode = existingSourceCode[:startPosition] + sourceCode + existingSourceCode[endPosition:]
v8Function.setSourceCode(newSourceCode)
v8Function.setPosition(startPosition, startPosition + len(sourceCode))</code></pre><p>Be careful, setSourceCode(String sourceCode) has radical impacts that may break the execution because all functions during one execution share the same source code but have their own positions. The following diagram shows the rough memory layout. Assuming function (4) has been changed to something else with position changed, function (1) and (2) will not be impacted because their positions remain the same, but function (3) will be broken because its end position is not changed to the end position of function (4) accordingly.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiiJpt3EvxijIu85xuC67MbUMl0z4urLIkfvASRvvpeL6ZGf3DI_9edpAcHTI7GB_CDibx68YkFr5Efvg_y-rEfPY2A8b2UIJU3jorX97mAwp527aXpCBY15UdqVFtmXDkn47CbZYJ7RBc/s690/memory_layout_of_v8_function.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="598" data-original-width="690" height="347" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiiJpt3EvxijIu85xuC67MbUMl0z4urLIkfvASRvvpeL6ZGf3DI_9edpAcHTI7GB_CDibx68YkFr5Efvg_y-rEfPY2A8b2UIJU3jorX97mAwp527aXpCBY15UdqVFtmXDkn47CbZYJ7RBc/w400-h347/memory_layout_of_v8_function.png" width="400" /></a></div><br /><p>Javet does not scan memory for all impacted function. So, it is caller's responsibility for restoring the original source code after invocation. The pseudo logic is as following.</p><pre class="java"><code>originalSourceCode = v8ValueFunction.getSourceCode()
v8ValueFunction.setSourceCode(sourceCode)
v8ValueFunction.call(...)
v8ValueFunction.setSourceCode(originalSourceCode)</code></pre><p>Why does setSourceCode() sometimes return false? Usually, that means the local scoped context hasn't been generated by V8. getJSScopeType().isClass() == true indicates that state. After callVoid(null), the local scoped context will be created with getJSScopeType().isFunction() == true and setSourceCode() will work. The pseudo logic is as following.</p><pre class="java"><code>originalSourceCode = v8ValueFunction.getSourceCode()
if (v8ValueFunction.getJSScopeType().isClass()) {
try {
v8ValueFunction.callVoid(null);
// Now v8ValueFunction.getJSScopeType().isFunction() is true
} catch (JavetException e) {
}
}
v8ValueFunction.setSourceCode(sourceCode) // true
v8ValueFunction.call(...)
v8ValueFunction.setSourceCode(originalSourceCode)</code></pre><p>The rough lifecycle of a V8 function is as following.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGKg6o7L7lH3kTch7395dgqTH5X5hknYK7yGpn74KIQRYCCXPSAbL28yINiMAu8Wpz70vWNda3i94LPJjK9j1-klp9NqRkvUropSx3512CKRLUEK1TwTdxNoJ5LoHgcqIS1mM5RDmle6c/s715/lifecycle_of_v8_function.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="605" data-original-width="715" height="339" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGKg6o7L7lH3kTch7395dgqTH5X5hknYK7yGpn74KIQRYCCXPSAbL28yINiMAu8Wpz70vWNda3i94LPJjK9j1-klp9NqRkvUropSx3512CKRLUEK1TwTdxNoJ5LoHgcqIS1mM5RDmle6c/w400-h339/lifecycle_of_v8_function.png" width="400" /></a></div><br /><h2 style="text-align: left;">What is the Source Code of a Function in V8?</h2><p>When V8 calculates start position of a function, it does not include the keyword function and function name. E.g.</p><pre class="javascript"><code>function abc(a, b, c) { ... } // Source code is (a, b, c) { ... }
(a, b, c) => { ... } // Source code is (a, b, c) => { ... }</code></pre><p>So, please always discard the keyword function and function name when calling setSourceCode().</p>Sam Caohttp://www.blogger.com/profile/03721092279920165184noreply@blogger.com0tag:blogger.com,1999:blog-6602054414215683748.post-14807479776609584932021-05-10T09:24:00.001+08:002021-05-10T09:24:24.851+08:00Javet — An awesome way of embedding Node.js and V8 in Java<p><a class="bv ib" href="https://github.com/caoccao/Javet/" rel="noopener nofollow" style="-webkit-tap-highlight-color: transparent; box-sizing: inherit; font-family: charter, Georgia, Cambria, "Times New Roman", Times, serif; font-size: 21px; letter-spacing: -0.003em;">Javet</a><span style="background-color: white; color: #292929; font-family: charter, Georgia, Cambria, "Times New Roman", Times, serif; font-size: 21px; letter-spacing: -0.003em;"> </span><span style="background-color: white; color: #292929; font-family: charter, Georgia, Cambria, "Times New Roman", Times, serif; font-size: 21px; letter-spacing: -0.003em;">is Java + V8 (JAVa + V + EighT). It is an awesome way of embedding Node.js and V8 in Java.</span></p><p class="hh hi fq hj b hk ic hl hm hn id ho hp hq ie hr hs ht if hu hv hw ig hx hy ia dh dy" data-selectable-paragraph="" id="e3b5" style="background-color: white; box-sizing: inherit; color: #292929; font-family: charter, Georgia, Cambria, "Times New Roman", Times, serif; font-size: 21px; letter-spacing: -0.003em; line-height: 32px; margin: 2em 0px -0.46em; word-break: break-word;">In Oct, 2020, I was looking for a solution about running JavaScript code in JVM with identical behavior as in a web browser. V8 seemed to be only candidate and the available solution was J2V8.</p><p class="hh hi fq hj b hk ic hl hm hn id ho hp hq ie hr hs ht if hu hv hw ig hx hy ia dh dy" data-selectable-paragraph="" id="fbed" style="background-color: white; box-sizing: inherit; color: #292929; font-family: charter, Georgia, Cambria, "Times New Roman", Times, serif; font-size: 21px; letter-spacing: -0.003em; line-height: 32px; margin: 2em 0px -0.46em; word-break: break-word;">However, J2V8 has dropped support for Linux in 2017 and Windows in 2016. The V8 doesn’t even completely support ES6.</p><p class="hh hi fq hj b hk ic hl hm hn id ho hp hq ie hr hs ht if hu hv hw ig hx hy ia dh dy" data-selectable-paragraph="" id="1c19" style="background-color: white; box-sizing: inherit; color: #292929; font-family: charter, Georgia, Cambria, "Times New Roman", Times, serif; font-size: 21px; letter-spacing: -0.003em; line-height: 32px; margin: 2em 0px -0.46em; word-break: break-word;">In Jan, 2021, I started an open-source project <a class="bv ib" href="https://github.com/caoccao/Javet/" rel="noopener nofollow" style="-webkit-tap-highlight-color: transparent; box-sizing: inherit;">https://github.com/caoccao/Javet/</a> from scratch. Now, it is fully functional and reaches production level.</p><h1 class="ih ii fq ba ij ik il hl im in io ho ip iq ir is it iu iv iw ix iy iz ja jb jc dy" data-selectable-paragraph="" id="6e86" style="background-color: white; box-sizing: inherit; color: #292929; font-family: sohne, "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 30px; font-weight: 500; line-height: 36px; margin: 1.95em 0px -0.28em;">Major Features</h1><ul class="" style="background-color: white; box-sizing: inherit; color: rgba(0, 0, 0, 0.8); font-family: medium-content-sans-serif-font, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; list-style: none none; margin: 0px; padding: 0px;"><li class="hh hi fq hj b hk jd hl hm hn je ho hp hq jf hr hs ht jg hu hv hw jh hx hy ia ji jj jk dy" data-selectable-paragraph="" id="7605" style="box-sizing: inherit; color: #292929; font-family: charter, Georgia, Cambria, "Times New Roman", Times, serif; font-size: 21px; letter-spacing: -0.003em; line-height: 32px; list-style-type: disc; margin-bottom: -0.46em; margin-left: 30px; margin-top: 0.86em; padding-left: 0px;">🐧Linux + 🖥️Windows</li><li class="hh hi fq hj b hk jl hl hm hn jm ho hp hq jn hr hs ht jo hu hv hw jp hx hy ia ji jj jk dy" data-selectable-paragraph="" id="8e3f" style="box-sizing: inherit; color: #292929; font-family: charter, Georgia, Cambria, "Times New Roman", Times, serif; font-size: 21px; letter-spacing: -0.003em; line-height: 32px; list-style-type: disc; margin-bottom: -0.46em; margin-left: 30px; margin-top: 1.05em; padding-left: 0px;">Node.js <code class="jq jr js jt ju b" style="background-color: #f2f2f2; box-sizing: inherit; font-family: Menlo, Monaco, "Courier New", Courier, monospace; font-size: 15.75px; padding: 2px 4px;">v14.16.1</code> + V8 <code class="jq jr js jt ju b" style="background-color: #f2f2f2; box-sizing: inherit; font-family: Menlo, Monaco, "Courier New", Courier, monospace; font-size: 15.75px; padding: 2px 4px;">v9.0.257</code></li><li class="hh hi fq hj b hk jl hl hm hn jm ho hp hq jn hr hs ht jo hu hv hw jp hx hy ia ji jj jk dy" data-selectable-paragraph="" id="1393" style="box-sizing: inherit; color: #292929; font-family: charter, Georgia, Cambria, "Times New Roman", Times, serif; font-size: 21px; letter-spacing: -0.003em; line-height: 32px; list-style-type: disc; margin-bottom: -0.46em; margin-left: 30px; margin-top: 1.05em; padding-left: 0px;">Dynamic switch between Node.js and V8</li><li class="hh hi fq hj b hk jl hl hm hn jm ho hp hq jn hr hs ht jo hu hv hw jp hx hy ia ji jj jk dy" data-selectable-paragraph="" id="1047" style="box-sizing: inherit; color: #292929; font-family: charter, Georgia, Cambria, "Times New Roman", Times, serif; font-size: 21px; letter-spacing: -0.003em; line-height: 32px; list-style-type: disc; margin-bottom: -0.46em; margin-left: 30px; margin-top: 1.05em; padding-left: 0px;">Exposure of the majority of V8 API in JVM</li><li class="hh hi fq hj b hk jl hl hm hn jm ho hp hq jn hr hs ht jo hu hv hw jp hx hy ia ji jj jk dy" data-selectable-paragraph="" id="0c4d" style="box-sizing: inherit; color: #292929; font-family: charter, Georgia, Cambria, "Times New Roman", Times, serif; font-size: 21px; letter-spacing: -0.003em; line-height: 32px; list-style-type: disc; margin-bottom: -0.46em; margin-left: 30px; margin-top: 1.05em; padding-left: 0px;">JS function interception</li><li class="hh hi fq hj b hk jl hl hm hn jm ho hp hq jn hr hs ht jo hu hv hw jp hx hy ia ji jj jk dy" data-selectable-paragraph="" id="c600" style="box-sizing: inherit; color: #292929; font-family: charter, Georgia, Cambria, "Times New Roman", Times, serif; font-size: 21px; letter-spacing: -0.003em; line-height: 32px; list-style-type: disc; margin-bottom: -0.46em; margin-left: 30px; margin-top: 1.05em; padding-left: 0px;">Native BigInt and Date</li><li class="hh hi fq hj b hk jl hl hm hn jm ho hp hq jn hr hs ht jo hu hv hw jp hx hy ia ji jj jk dy" data-selectable-paragraph="" id="f40c" style="box-sizing: inherit; color: #292929; font-family: charter, Georgia, Cambria, "Times New Roman", Times, serif; font-size: 21px; letter-spacing: -0.003em; line-height: 32px; list-style-type: disc; margin-bottom: -0.46em; margin-left: 30px; margin-top: 1.05em; padding-left: 0px;">Javet engine pool</li><li class="hh hi fq hj b hk jl hl hm hn jm ho hp hq jn hr hs ht jo hu hv hw jp hx hy ia ji jj jk dy" data-selectable-paragraph="" id="2f03" style="box-sizing: inherit; color: #292929; font-family: charter, Georgia, Cambria, "Times New Roman", Times, serif; font-size: 21px; letter-spacing: -0.003em; line-height: 32px; list-style-type: disc; margin-bottom: -0.46em; margin-left: 30px; margin-top: 1.05em; padding-left: 0px;">Easy spring integration</li><li class="hh hi fq hj b hk jl hl hm hn jm ho hp hq jn hr hs ht jo hu hv hw jp hx hy ia ji jj jk dy" data-selectable-paragraph="" id="4a0a" style="box-sizing: inherit; color: #292929; font-family: charter, Georgia, Cambria, "Times New Roman", Times, serif; font-size: 21px; letter-spacing: -0.003em; line-height: 32px; list-style-type: disc; margin-bottom: -0.46em; margin-left: 30px; margin-top: 1.05em; padding-left: 0px;">Live debug with Chrome DevTools</li></ul><h1 class="ih ii fq ba ij ik il hl im in io ho ip iq ir is it iu iv iw ix iy iz ja jb jc dy" data-selectable-paragraph="" id="861a" style="background-color: white; box-sizing: inherit; color: #292929; font-family: sohne, "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 30px; font-weight: 500; line-height: 36px; margin: 1.95em 0px -0.28em;">Quick Start</h1><h1 class="ih ii fq ba ij ik il hl im in io ho ip iq ir is it iu iv iw ix iy iz ja jb jc dy" data-selectable-paragraph="" id="963e" style="background-color: white; box-sizing: inherit; color: #292929; font-family: sohne, "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 30px; font-weight: 500; line-height: 36px; margin: 1.95em 0px -0.28em;">Dependency</h1><h2 class="jv ii fq ba ij jw jx jy im jz ka kb ip kc kd ke it kf kg kh ix ki kj kk jb kl dy" data-selectable-paragraph="" id="4316" style="background-color: white; box-sizing: inherit; color: #292929; font-family: sohne, "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 22px; font-weight: 500; line-height: 28px; margin: 1.72em 0px -0.31em;">Maven</h2><pre class="km kn ko kp kq kr ks kt" style="background: rgb(242, 242, 242); box-sizing: inherit; color: rgba(0, 0, 0, 0.8); margin-bottom: 0px; margin-top: 56px; overflow-x: auto; padding: 20px;"><span class="dy jv ii fq ju b di ku kv s kw" data-selectable-paragraph="" id="c3eb" style="box-sizing: inherit; color: #292929; display: block; font-family: Menlo, Monaco, "Courier New", Courier, monospace; font-size: 16px; letter-spacing: -0.022em; line-height: 1.18; margin-bottom: -0.09em; margin-top: -0.09em; white-space: pre-wrap;"><dependency><br style="box-sizing: inherit;" /> <groupId>com.caoccao.javet</groupId><br style="box-sizing: inherit;" /> <artifactId>javet</artifactId><br style="box-sizing: inherit;" /> <version>0.8.7</version><br style="box-sizing: inherit;" /></dependency></span></pre><h2 class="jv ii fq ba ij jw jx jy im jz ka kb ip kc kd ke it kf kg kh ix ki kj kk jb kl dy" data-selectable-paragraph="" id="1017" style="background-color: white; box-sizing: inherit; color: #292929; font-family: sohne, "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 22px; font-weight: 500; line-height: 28px; margin: 1.72em 0px -0.31em;">Gradle Kotlin DSL</h2><pre class="km kn ko kp kq kr ks kt" style="background: rgb(242, 242, 242); box-sizing: inherit; color: rgba(0, 0, 0, 0.8); margin-bottom: 0px; margin-top: 56px; overflow-x: auto; padding: 20px;"><span class="dy jv ii fq ju b di ku kv s kw" data-selectable-paragraph="" id="c1aa" style="box-sizing: inherit; color: #292929; display: block; font-family: Menlo, Monaco, "Courier New", Courier, monospace; font-size: 16px; letter-spacing: -0.022em; line-height: 1.18; margin-bottom: -0.09em; margin-top: -0.09em; white-space: pre-wrap;">implementation("com.caoccao.javet:javet:0.8.7")</span></pre><h2 class="jv ii fq ba ij jw jx jy im jz ka kb ip kc kd ke it kf kg kh ix ki kj kk jb kl dy" data-selectable-paragraph="" id="645d" style="background-color: white; box-sizing: inherit; color: #292929; font-family: sohne, "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 22px; font-weight: 500; line-height: 28px; margin: 1.72em 0px -0.31em;">Gradle Groovy DSL</h2><pre class="km kn ko kp kq kr ks kt" style="background: rgb(242, 242, 242); box-sizing: inherit; color: rgba(0, 0, 0, 0.8); margin-bottom: 0px; margin-top: 56px; overflow-x: auto; padding: 20px;"><span class="dy jv ii fq ju b di ku kv s kw" data-selectable-paragraph="" id="c335" style="box-sizing: inherit; color: #292929; display: block; font-family: Menlo, Monaco, "Courier New", Courier, monospace; font-size: 16px; letter-spacing: -0.022em; line-height: 1.18; margin-bottom: -0.09em; margin-top: -0.09em; white-space: pre-wrap;">implementation 'com.caoccao.javet:javet:0.8.7'</span></pre><h1 class="ih ii fq ba ij ik il hl im in io ho ip iq ir is it iu iv iw ix iy iz ja jb jc dy" data-selectable-paragraph="" id="030e" style="background-color: white; box-sizing: inherit; color: #292929; font-family: sohne, "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 30px; font-weight: 500; line-height: 36px; margin: 1.95em 0px -0.28em;">Hello Javet</h1><pre class="km kn ko kp kq kr ks kt" style="background: rgb(242, 242, 242); box-sizing: inherit; color: rgba(0, 0, 0, 0.8); margin-bottom: 0px; margin-top: 56px; overflow-x: auto; padding: 20px;"><span class="dy jv ii fq ju b di ku kv s kw" data-selectable-paragraph="" id="a1d2" style="box-sizing: inherit; color: #292929; display: block; font-family: Menlo, Monaco, "Courier New", Courier, monospace; font-size: 16px; letter-spacing: -0.022em; line-height: 1.18; margin-bottom: -0.09em; margin-top: -0.09em; white-space: pre-wrap;">// Node.js Mode<br style="box-sizing: inherit;" />try (V8Runtime v8Runtime = V8Host.getNodeInstance().createV8Runtime()) {<br style="box-sizing: inherit;" /> System.out.println(v8Runtime.getExecutor("'Hello Javet'").executeString());<br style="box-sizing: inherit;" />}</span><span class="dy jv ii fq ju b di kx ky kz la lb kv s kw" data-selectable-paragraph="" id="d4c8" style="box-sizing: inherit; color: #292929; display: block; font-family: Menlo, Monaco, "Courier New", Courier, monospace; font-size: 16px; letter-spacing: -0.022em; line-height: 1.18; margin-bottom: -0.09em; margin-top: 1.91em; white-space: pre-wrap;">// V8 Mode<br style="box-sizing: inherit;" />try (V8Runtime v8Runtime = V8Host.getV8Instance().createV8Runtime()) {<br style="box-sizing: inherit;" /> System.out.println(v8Runtime.getExecutor("'Hello Javet'").executeString());<br style="box-sizing: inherit;" />}</span></pre>Sam Caohttp://www.blogger.com/profile/03721092279920165184noreply@blogger.com0tag:blogger.com,1999:blog-6602054414215683748.post-88120036987246584202021-05-08T15:59:00.003+08:002021-05-08T15:59:50.996+08:00Javet v0.8.7 is released.<p> </p><p><span style="background-color: white; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; font-size: 16px;">Javet is Java + V8 (JAVa + V + EighT). It is an awesome way of embedding Node.js and V8 in Java.</span></p><p>For more detail, please visit https://github.com/caoccao/Javet</p>Sam Caohttp://www.blogger.com/profile/03721092279920165184noreply@blogger.com0tag:blogger.com,1999:blog-6602054414215683748.post-359333317220920202021-05-03T08:02:00.000+08:002021-05-03T08:02:00.072+08:00Fix: Intellij IDEA BindException Address already in use<p> Have you even met <span style="color: red;"><b>Address already in use</b></span> on Windows?</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFLjLVFYlvfraSkN173CrKEc6VoTUPPpkasEme5D0UgZgUk0VKdGHKNxMahoaWpOwC5fV25YzyXSCeXBvAnCltYRt2oln0yl5WkkjbGmmn7Vymz0eumu3ovHaiXQyFWSwhHSSYDVBdjmA/s704/J-Jb56YgLTS4g3upsjd2kQ.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="581" data-original-width="704" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFLjLVFYlvfraSkN173CrKEc6VoTUPPpkasEme5D0UgZgUk0VKdGHKNxMahoaWpOwC5fV25YzyXSCeXBvAnCltYRt2oln0yl5WkkjbGmmn7Vymz0eumu3ovHaiXQyFWSwhHSSYDVBdjmA/s16000/J-Jb56YgLTS4g3upsjd2kQ.png" /></a></div><br /><p>The fix is very simple with the following 2 commands.</p><div style="text-align: left;"><span style="font-family: courier;">net stop winnat<br /></span><span style="font-family: courier;">net start winnat</span></div><p><br /><br /></p>Sam Caohttp://www.blogger.com/profile/03721092279920165184noreply@blogger.com0tag:blogger.com,1999:blog-6602054414215683748.post-35042909999426894052021-04-27T14:21:00.002+08:002021-04-27T16:31:27.168+08:00What's Wrong with GLIBCXX_3.4.26?<p>If you met the following error, please check this <a href="https://github.com/caoccao/Javet/discussions/26" target="_blank">post</a> out for a solution.</p><blockquote style="background-color: white; border-left: 0.25em solid var(--color-markdown-blockquote-border); box-sizing: border-box; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; font-size: 14px; margin: 0px 0px 16px; padding: 0px 1em; tab-size: var(--tab-size) !important;"><p style="box-sizing: border-box; margin-bottom: 0px; margin-top: 0px; tab-size: var(--tab-size) !important;"><span style="color: #cc0000;">java.lang.UnsatisfiedLinkError: /tmp/libjavet-v8-linux-x86_64.v.0.8.4.so: /usr/lib/x86_64-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.26' not found (required by /tmp/libjavet-v8-linux-x86_64.v.0.8.4.so)</span></p></blockquote>Sam Caohttp://www.blogger.com/profile/03721092279920165184noreply@blogger.com0tag:blogger.com,1999:blog-6602054414215683748.post-12220907871284691282021-04-24T20:54:00.003+08:002021-04-24T20:55:51.272+08:00Javet v0.8.4 is Released<p> </p><ul style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; font-size: 16px; margin-bottom: 16px; margin-top: 0px; padding-left: 2em;"><li style="box-sizing: border-box;">Upgraded Node.js to <code style="background-color: var(--color-markdown-code-bg); border-radius: 6px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;">v14.16.1</code> (2021-04-06)</li><li style="box-sizing: border-box; margin-top: 0.25em;">Upgraded V8 to <code style="background-color: var(--color-markdown-code-bg); border-radius: 6px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;">v9.0.257</code> (2021-02-24)</li></ul><div><span face="-apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji" style="color: #24292e;"><a href="https://github.com/caoccao/Javet/">https://github.com/caoccao/Javet/</a></span></div>Sam Caohttp://www.blogger.com/profile/03721092279920165184noreply@blogger.com0tag:blogger.com,1999:blog-6602054414215683748.post-76627961362277308862021-04-13T16:16:00.004+08:002021-04-13T16:16:24.941+08:00Javet v0.8.3 is released<ul style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; font-size: 16px; margin-bottom: 0px !important; margin-top: 0px !important; padding-left: 2em; tab-size: var(--tab-size) !important;"><li style="box-sizing: border-box; tab-size: var(--tab-size) !important;">Added <code style="background-color: var(--color-markdown-code-bg); border-radius: 6px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em; tab-size: var(--tab-size) !important;">V8Runtime.lowMemoryNotification()</code> and <code style="background-color: var(--color-markdown-code-bg); border-radius: 6px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em; tab-size: var(--tab-size) !important;">V8Runtime.idleNotificationDeadline()</code></li><li style="box-sizing: border-box; margin-top: 0.25em; tab-size: var(--tab-size) !important;">Added <code style="background-color: var(--color-markdown-code-bg); border-radius: 6px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em; tab-size: var(--tab-size) !important;">V8Host.setMemoryUsageThresholdRatio()</code>, <code style="background-color: var(--color-markdown-code-bg); border-radius: 6px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em; tab-size: var(--tab-size) !important;">V8Host.enableGCNotification()</code>, and <code style="background-color: var(--color-markdown-code-bg); border-radius: 6px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em; tab-size: var(--tab-size) !important;">V8Host.disableGCNotification()</code></li><li style="box-sizing: border-box; margin-top: 0.25em; tab-size: var(--tab-size) !important;">Updated JavetEnginePool to be lock free</li><li style="box-sizing: border-box; margin-top: 0.25em; tab-size: var(--tab-size) !important;">Added <code style="background-color: var(--color-markdown-code-bg); border-radius: 6px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em; tab-size: var(--tab-size) !important;">autoSendGCNotification</code> to <code style="background-color: var(--color-markdown-code-bg); border-radius: 6px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em; tab-size: var(--tab-size) !important;">JavetEngineConfig</code></li><li style="box-sizing: border-box; margin-top: 0.25em; tab-size: var(--tab-size) !important;">Moved <code style="background-color: var(--color-markdown-code-bg); border-radius: 6px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em; tab-size: var(--tab-size) !important;">JavetCallbackContext</code> management from <code style="background-color: var(--color-markdown-code-bg); border-radius: 6px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em; tab-size: var(--tab-size) !important;">V8ValueFunction</code> to V8</li><li style="box-sizing: border-box; margin-top: 0.25em; tab-size: var(--tab-size) !important;">Added <code style="background-color: var(--color-markdown-code-bg); border-radius: 6px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em; tab-size: var(--tab-size) !important;">JavetPromiseRejectCallback</code> for V8 mode</li></ul><div><span style="color: #24292e; font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji;"><br /></span></div><div><span style="color: #24292e; font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji;">https://github.com/caoccao/Javet/</span></div>Sam Caohttp://www.blogger.com/profile/03721092279920165184noreply@blogger.com0