<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Pramoth Suwanpech</title>
    <description>The latest articles on DEV Community by Pramoth Suwanpech (@pramoth).</description>
    <link>https://dev.to/pramoth</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F57947%2F5bd1ff2c-c35b-4dac-80c1-926703a70c42.jpg</url>
      <title>DEV Community: Pramoth Suwanpech</title>
      <link>https://dev.to/pramoth</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pramoth"/>
    <language>en</language>
    <item>
      <title>ติดตั้ง Realtek R8125 บน AlmaLinux 10</title>
      <dc:creator>Pramoth Suwanpech</dc:creator>
      <pubDate>Wed, 08 Oct 2025 15:36:00 +0000</pubDate>
      <link>https://dev.to/pramoth/tidtang-realtek-r8125-bn-almalinux-10-1bon</link>
      <guid>https://dev.to/pramoth/tidtang-realtek-r8125-bn-almalinux-10-1bon</guid>
      <description>&lt;p&gt;พอดีซื้อ mainboad ทีมี network card เป็น R8125 แล้วมันไม่ทำงานเนื่องจากไม่มี driver&lt;br&gt;
ค้าหาวิธีทำนานเลย จดไว้หน่อย&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;ติดตั้ง repo เป็ร 3rd party ระวังเอง ไม่งั้นก็ไปโหลดมา compileเอง ต้องไปโหลดข้อมูลในเน็ต การ์ดแลนใช้ไม่ได้ จะต้องไปหา usb มาใช้ติดตั้งก่อน
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dnf install http://mirror.rackspace.com/elrepo/elrepo/el10/x86_64/RPMS/elrepo-release-10.0-1.el10.elrepo.noarch.rpm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt; &lt;code&gt;sudo dnf install kmod-r8125&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sudo modprobe r8125&lt;/code&gt; ถ้ามี sign เออเร่อไปปิด secure boot ไม่งั้นต้องไปทำ sign kernel module&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;nmcli device show&lt;/code&gt; ควรจะเห็นแระ&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;nmcli device connect &amp;lt;device name&amp;gt;&lt;/code&gt; ปล. มันได้ ip มาสักพักถึงจะต่อได้&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>linux</category>
      <category>networking</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>ติดตั้ง thai locale ใน CenOS/Alma/Rocky linux ใน docker</title>
      <dc:creator>Pramoth Suwanpech</dc:creator>
      <pubDate>Sun, 09 Jun 2024 10:43:10 +0000</pubDate>
      <link>https://dev.to/pramoth/tidtang-thai-locale-ain-cenosalmarocky-linux-ain-docker-19n4</link>
      <guid>https://dev.to/pramoth/tidtang-thai-locale-ain-cenosalmarocky-linux-ain-docker-19n4</guid>
      <description>&lt;p&gt;วันนี้ลองเล่น almalinux 9.4 image แล้วมันไม่ได้มี locale thai มาให้ จะติดตั้งก็ง่ายๆด้วยคำสั่ง &lt;code&gt;localectl&lt;/code&gt; เพราะว่าอยู่ใน container จึง research หาสักพักเลย จึงจะ note ไว้หน่อยละกัน&lt;/p&gt;

&lt;p&gt;almalinux image ไม่ได้ใส่ avialable locale มาให้เรามันมีแค่ POSIX locale ดังนั้นเราต้องติดตั้งเพิ่ม เราเช็คได้ว่ามันมี avialable locale อะไรมาให้บ้างด้วย &lt;code&gt;locale -a&lt;/code&gt;&lt;br&gt;
ซึ่งจะมีแค่&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[root@d121e84764c6 /]# locale -a
C
C.utf8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;locale file ของ avialable locale Redhat จะอยู่ที่ และ &lt;code&gt;/usr/share/i18n/locales&lt;/code&gt;&lt;br&gt;
 file chracter map จะอยู่ที่ &lt;code&gt;/usr/share/i18n/charmaps&lt;/code&gt; ถ้าเรา &lt;code&gt;ls&lt;/code&gt; ดูน่าจะยังไม่มีเลย&lt;br&gt;
การติดตั้งก็หา package มาลงตามนี้&lt;br&gt;
&lt;code&gt;yum -y install glibc-locale-source glibc-langpack-en glibc-langpack-th&lt;/code&gt; ซึ่งภาษาไทยก็จะอยู่ใน package &lt;code&gt;glibc-langpack-th&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;หลังจากติดตั้งแล้ว เราลอง list avialable locale อีกที&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[root@13c0780e7ad2 /]# locale -a
...
...
th_TH
th_TH.utf8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จากนั้นเราก็ใช้ได้เลย โดย set environmant var LANG&lt;br&gt;
&lt;code&gt;export LANG=th_TH&lt;/code&gt;&lt;br&gt;
แล้วเช็ค locale ของ current terminal เราด้วย &lt;code&gt;locale&lt;/code&gt; จะได้ตามนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[root@13c0780e7ad2 /]# locale
LANG=th_TH.utf8
LC_CTYPE="th_TH.utf8"
LC_NUMERIC="th_TH.utf8"
LC_TIME="th_TH.utf8"
LC_COLLATE="th_TH.utf8"
LC_MONETARY="th_TH.utf8"
LC_MESSAGES="th_TH.utf8"
LC_PAPER="th_TH.utf8"
LC_NAME="th_TH.utf8"
LC_ADDRESS="th_TH.utf8"
LC_TELEPHONE="th_TH.utf8"
LC_MEASUREMENT="th_TH.utf8"
LC_IDENTIFICATION="th_TH.utf8"
LC_ALL=
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เป็นอันว่าเรียบร้อย ที่เหลือก็ไปเซ็ตให้มันใช้ได้กับทุกๆ user ในไฟล์ &lt;code&gt;/etc/locale.conf&lt;/code&gt; หรือ per user ในไฟล์ &lt;code&gt;$HOME/.i18n&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;note&lt;/strong&gt; locale package ของฝั่ง ubuntu จะเป็น &lt;strong&gt;language-pack-XX&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;อ้างอิง&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/58304278/how-to-fix-character-map-file-utf-8-not-found"&gt;https://stackoverflow.com/questions/58304278/how-to-fix-character-map-file-utf-8-not-found&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://access.redhat.com/solutions/974273"&gt;https://access.redhat.com/solutions/974273&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>เริ่มต้น Quarkus 3 part 2.3 Renarde</title>
      <dc:creator>Pramoth Suwanpech</dc:creator>
      <pubDate>Tue, 04 Jun 2024 16:34:08 +0000</pubDate>
      <link>https://dev.to/pramoth/erimtn-quarkus-3-part-23-renarde-2bgd</link>
      <guid>https://dev.to/pramoth/erimtn-quarkus-3-part-23-renarde-2bgd</guid>
      <description>&lt;p&gt;Renarde เป็นอีกตัวช่วยในการทำ SSR ในรูปแบบ MVC เช่นเดียวกับ Spring MVC ที่มีเครื่องมือให้พร้อมหยิบมาใช้งานเลย เช่น form validator,csrf,routing,email,htmx support,barcode,gen pdf,security.... &lt;/p&gt;

&lt;p&gt;เริ่มต้นใช้งานก็เพิ่ม dependency ใน pom.xml จากบทความก่อนๆได้เลย โดยคง web-bundler ไว้เหมือนเดิม แต่สามารถเอา qute-web ,rest-qute ออกได้เลยเพราะมี transitive dependency จาก renarde ไปแล้ว&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;        &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;io.quarkiverse.renarde&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;quarkus-renarde&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;3.0.12&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จากนั้นจะต้องไป disable proactive authen ก่อน เพราะว่าเรายังไม่ได้ config security จะเข้า endpoint ไม่ได้เพราะมัน enable by default&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;quarkus.http.auth.proactive=false
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ที่เหลือก็เหมือน Action based MVC ทั่วๆไปนะครับ รยละเอียดแนะนำให้ไปโหลด เดโมมาลองที่&lt;br&gt;
&lt;a href="https://github.com/ia3andy/quarkus-blast"&gt;https://github.com/ia3andy/quarkus-blast&lt;/a&gt; จะเป็น Renarde+HTMX ครับ&lt;/p&gt;

</description>
      <category>quarkus</category>
    </item>
    <item>
      <title>เริ่มต้น Quarkus 3 part 2.2 web bundler</title>
      <dc:creator>Pramoth Suwanpech</dc:creator>
      <pubDate>Tue, 04 Jun 2024 15:21:06 +0000</pubDate>
      <link>https://dev.to/pramoth/erimtn-quarkus-3-part-2-web-bundler-1fdk</link>
      <guid>https://dev.to/pramoth/erimtn-quarkus-3-part-2-web-bundler-1fdk</guid>
      <description>&lt;p&gt;หลังจากที่เราได้ serverside rendering Qute แล้วจากบทความก่อนหน้านี้ &lt;a href="https://dev.to/pramoth/erimtn-quarkus-3-part-2-web-4bkm"&gt;https://dev.to/pramoth/erimtn-quarkus-3-part-2-web-4bkm&lt;/a&gt; ในบทความนี้เราจะเอา javascript dependencies (npm) เข้ามาใช้ใน Qute template โดยใช้ตัวช่วยที่ชื่อว่า Web Bundler ซึ่งเจ้าตัวนี้จะใช้ mvnpm(ก็เหมือน webjar แต่ว่ามันสร้าง jar auto ฉนั้นมันจึงมี version ใหม่ๆมาเร็วเท่ากับใน npm registry เลยทีเดียว&lt;/p&gt;

&lt;p&gt;ในบทความนี้เราจะลองทำ Hello world ด้วย AlpineJS กันครับ&lt;br&gt;
เริ่มต้นเพิ่ม Web Bundler dependency ใน pom.xml ตามนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;io.quarkiverse.web-bundler&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;quarkus-web-bundler&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.5.2&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จากนั้นเราก็ไปหา npm ที่เราจะใช้งาน แต่ว่าไปหาจากเวบ &lt;a href="https://mvnpm.org/"&gt;https://mvnpm.org/&lt;/a&gt; นะครับ ก็ค้นหาชื่อตาม npm registry นั้นแหละ&lt;br&gt;
จากนั้นก็เอามาใส่ใน pom.xml&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.mvnpm&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;alpinejs&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;3.14.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;provided&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;แน่นอนว่าไม่ต้อง restart quarkus เหมือนเดิม มันจะ load dependencies แล้ว reload ให้เลย&lt;br&gt;
เจ้า Web Bundler จะไปหา js ที่เป็น entry point โดยจะหาจากไฟล์ใน src/main/resources/web/app/** &lt;br&gt;
ให้เราสร้างไฟล์ index.js ขึ้นมาโดยมี content โดย import Alpinejs มาใช้งานตามเอกสารของเขา ดังนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Alpine&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;alpinejs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Alpine&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Alpine&lt;/span&gt;
&lt;span class="nx"&gt;Alpine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จากนั้นให้เอา &lt;code&gt;{#bundler /}&lt;/code&gt; ไปใส่ใน hello.html&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    {#bundle /}
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
....
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เมื่อเรา refresh /hello เราจะพบว่า js ของเราถูก import เข้าไปที่หน้า index พร้อมกับ dependencies!! ง่ายสุดๆ&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx8g278lz1o6ondlfa6qh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx8g278lz1o6ondlfa6qh.png" alt="Image description" width="800" height="182"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ทดลองใส่ alpinejs ไปใน body&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;x-data=&lt;/span&gt;&lt;span class="s"&gt;"{ count: 0 }"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;x-on:click=&lt;/span&gt;&lt;span class="s"&gt;"count++"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Increment&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;x-text=&lt;/span&gt;&lt;span class="s"&gt;"count"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;refresh แล้วดูผลลัพธืได้ทันที ว้าววว&lt;/p&gt;

&lt;p&gt;ปล. สำหรับใครที่หา dependencies mvnpm ไม่เจอให้ไปเพิ่ม repo ตามเอกสารจากเวบนี้นะครับ&lt;br&gt;
&lt;a href="https://docs.quarkiverse.io/quarkus-web-bundler/dev/advanced-guides.html"&gt;https://docs.quarkiverse.io/quarkus-web-bundler/dev/advanced-guides.html&lt;/a&gt;&lt;/p&gt;

</description>
      <category>quarkus</category>
    </item>
    <item>
      <title>เริ่มต้น Quarkus 3 part 2.1 Web</title>
      <dc:creator>Pramoth Suwanpech</dc:creator>
      <pubDate>Sun, 02 Jun 2024 07:54:03 +0000</pubDate>
      <link>https://dev.to/pramoth/erimtn-quarkus-3-part-2-web-4bkm</link>
      <guid>https://dev.to/pramoth/erimtn-quarkus-3-part-2-web-4bkm</guid>
      <description>&lt;p&gt;ใน part นี้เราจะเริ่มเพิ่ม html template Qute เพื่อให้ render html ที่ server side&lt;/p&gt;

&lt;p&gt;เริ่ม !&lt;br&gt;
&lt;code&gt;quarkus dev&lt;/code&gt; ก่อนเลย เพราะว่ามันจะ auto reload dependency ให้ด้วย สุดยอดดดด&lt;/p&gt;

&lt;p&gt;จากนั้นเราแก้ pom.xml โดยเพิ่ม&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;io.quarkiverse.qute.web&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;quarkus-qute-web&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เมื่อเซฟมันก็จะไปโหลด deps มาให้เลย (เราไม่ต้องสนใจ dev ต่อ)&lt;br&gt;
เราเริ่มสร้าง template แรกเลยโดย qute จะไปอ่าน template จาก 2 ที่ด้วยกัน&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;แบบไม่มี controller มันจะไปอ่านที่ &lt;code&gt;src/main/resource/templates/pub/&lt;/code&gt; เวลาเข้าถึงก็เข้าถึงได้ตรงๆ ที่ path /file เลย เช่น &lt;code&gt;src/main/resource/templates/pub/foo.html&lt;/code&gt; จะเข้าถึงได้ที่ &lt;code&gt;/foo&lt;/code&gt; and &lt;code&gt;/foo.html&lt;/code&gt; ได้เลย&lt;/li&gt;
&lt;li&gt;แบบอ้างอิงกับ Rest controller อันนี้เราจะวางที่ &lt;code&gt;src/main/resources/templates&lt;/code&gt; และเข้าถึงผ่าน rest endpoint ของเรา&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;เราเน้นแบบ rest นะ(ใน part1 เรามี rest ใน project แล้ว)&lt;br&gt;
ให้เราเพิ่ม controller แบบนี้ (ลบ GreetingResource ออกด้วยนะครับ มันพาธเดียวกัน)&lt;br&gt;
ดังนั้น เพื่อให้มันรองรับ rest endpoint แบบไม่ต้องเมนวลให้เพิ่ม&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;       &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;io.quarkus&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;quarkus-rest-qute&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;ใน &lt;a href="https://quarkus.io/guides/qute"&gt;https://quarkus.io/guides/qute&lt;/a&gt; เขาไม่ได้ใส่ quarkus-rest-qute คิดว่าเอกสารผิดนะ ถ้าไม่ใส่ เราต้องเรียก TemplateInstance.data().render() เอง ContainerResponseFilter จะไม่ทำงาน&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Folal92nxfwxi6xgvfmxc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Folal92nxfwxi6xgvfmxc.png" alt="Image description" width="800" height="249"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ที่ capture รูปมาให้ดูเพราะจะได้เห็น template path จากในโค๊ด &lt;code&gt;@Inject Template hello&lt;/code&gt; เป็นการ inject qute template instance เข้ามา ซึ่ง template file เราอยู่ที่ &lt;code&gt;src/main/resources/templates/hello.html&lt;/code&gt; ซึ่งจะชื่อเดียวกับ instance variable(hello)  ถ้าเราอยาก custom path ให้ใช้ &lt;code&gt;@Location&lt;/code&gt;&lt;br&gt;
มาดู hello.html กัน&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Hello {name}!&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จะมีการใช้ Qute expression {name} ซึ่งกันนี้เราจะส่งเป็นพรามิเตอร์มาจาก cpntroller จากตรงนี้ &lt;code&gt;return hello.data("name", name);&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Type-safe templates
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;เราจะจัดโครงสร้าง directory ด้วย &lt;code&gt;ชื่อคลาส/template_method&lt;/code&gt; เช่น คลาส HelloResource และมี template method ชื่อ hello เทมเพลทจะอยู่ &lt;code&gt;src/main/resources/templates/HelloResource/hello.html&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;ให้สร้าง static inner class Rest controller &lt;code&gt;@CheckedTemplate static class Template {}&lt;/code&gt; ซึ่งให้กำหนด template method ไว้ในนั้น&lt;/li&gt;
&lt;li&gt;method กำหนด แบบนี้ &lt;code&gt;public static native TemplateInstance template_method_name(String  template_param)&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;ตัวอย่าง&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjy1sm6zph3pi7s0eiff2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjy1sm6zph3pi7s0eiff2.png" alt="Image description" width="709" height="391"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;อ้างอิง &lt;br&gt;
&lt;a href="https://quarkus.io/guides/qute"&gt;https://quarkus.io/guides/qute&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;part 1 &lt;a href="https://dev.to/pramoth/erimtn-quarkus-3-part-1-ane"&gt;https://dev.to/pramoth/erimtn-quarkus-3-part-1-ane&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>เริ่มต้น Quarkus 3 part 1</title>
      <dc:creator>Pramoth Suwanpech</dc:creator>
      <pubDate>Sun, 02 Jun 2024 06:55:51 +0000</pubDate>
      <link>https://dev.to/pramoth/erimtn-quarkus-3-part-1-ane</link>
      <guid>https://dev.to/pramoth/erimtn-quarkus-3-part-1-ane</guid>
      <description>&lt;p&gt;blog นี้จะพาเรียนรู้ quarkus step by step เพราะว่าการเริ่มต้น Quarkus มันมีหลาย plugin มากทำให้คนที่เริ่มเรียนจับต้นชนปลายยาก ผมจึงจะจะเอามาเรียบเรียง เริ่มทำตั้งแต่เริ่มต้น โดยเราจะทำ web app ที่ render ด้วย server side โดยใช้ Qute template engine หน้าบ้านใช้ HTMX,AlpineJS &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Rest&lt;/li&gt;
&lt;li&gt;web (static,server side rendering)

&lt;ul&gt;
&lt;li&gt;Qute&lt;/li&gt;
&lt;li&gt;web bundler&lt;/li&gt;
&lt;li&gt;Renarde&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;hibernate orm &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;ทีมผมใช้ Spring boot เป็นหลัก แต่ในปีนี้เรามีบางส่วนจะย้ายมา Quarkus เพราะว่าเราต้องการ dev ที่เร็วซึ่ง quarkus มำ livereload ได้ดีมากๆอารมร์เหมือนเขียนพวก dynamic lang เลย&lt;br&gt;
อีกประเด็นที่เราเลือก Quarkus ก็คือ เราต้องการใช้ server side renderer เราจึงต้องการ template engine แต่เราต้องการ template engine ที่ &lt;strong&gt;typesafety&lt;/strong&gt; เมื่อหาอยู่นาน java template engine ที่ typesafe ก็จะมีแค่ jsp และ qute เท่านั้น &lt;br&gt;
ส่วนเรื่อง performance ของ Quarkus ที่ดีกว่า boot นั้นไม่ได้เป็นจุดที่เราเลือก เพราะว่ามันไม่ได้สำคัญในแง่มากใน enterprise app ที่เราทำไป optimize หลังบ้านให้ดีๆ ดีกว่า แต่ก็ถือว่าดีที่ได้ความเร็วเพิ่มมา&lt;/p&gt;
&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;Quarkus จะต่างจาก boot ตรงที่มันจะทำการ&lt;strong&gt;build&lt;/strong&gt;หรือประกอบร่าง bean ต่างๆตอน build เช่น แทนที่จะ scan หา annotation &lt;code&gt;@Entity&lt;/code&gt; ตอน start app มันก็หาตอน build แล้วเตียม code ที่ setup EntityManager ให้เลยตอนรันก็พร้อมใช้เลย ข้อดีทำให้ start เร็วและสามารถขจัดโค๊ดที่ไม่ได้ใช้ และยังเป็นการเตรียมพร้อมกับการทำ native image ได้ด้วย(เพราะ build image ต้องการรู้ว่าจะใช้ควาสไหนตอน build เช่นกัน) &lt;/p&gt;
&lt;h2&gt;
  
  
  Part1 Rest
&lt;/h2&gt;

&lt;p&gt;หลังจากติดตั้ง quarkus CLI แล้ว ก็เริ่มใช้สร้าง project เลยครับโดยใช้คำสั่ง&lt;br&gt;
&lt;code&gt;quarkus create app th.co.geniustree.quarkus:demo1 -P 3.11.0&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;quarkus create&lt;/code&gt; จะใช้สร้าง project โดยโปรเจคจะมี 3 แบบ app,extension,cli เราจะสร้างเวบแอพ เราเลือก app (ส่วน extension สำหรับคนที่จะทำปลั๊กอิน quarkus เด๋วเราจะมีทำในขั้น advance) สำหรับ cli ก็ตามชื่อเลย ส่วน &lt;code&gt;-P 3.11.0&lt;/code&gt; จะบกว่าเราจะใช้ quarkus platform version อะไร (เครื่องผม quarkus cli เจน version เก่าให้ตลอด)&lt;/p&gt;

&lt;p&gt;เราจะได้ project maven ที่มี Rest controller มาให้ Quarkus จะใช้ microprofile api ซึ่งเป็น subset ของ JakataEE  แทน spring&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Path&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/hello"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GreetingResource&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@GET&lt;/span&gt;
    &lt;span class="nd"&gt;@Produces&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MediaType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;TEXT_PLAIN&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Hello from Quarkus REST"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เราสารถรันใน dev โหมดโดย &lt;code&gt;quarkus dev&lt;/code&gt; แล้วลองเข้า &lt;a href="http://localhost:8080"&gt;http://localhost:8080&lt;/a&gt; จะเห็น devUI ของ Quarkus ซึ่งมี rest endpoint /hello อยู่&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fovw6vdmmzv0pjsv16sa2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fovw6vdmmzv0pjsv16sa2.png" alt="Image description" width="800" height="123"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ให้ทดลองแก้โค๊ด แล้วยิง rest ใหม่ มันจะ auto reload ให้ความรู้สึกฟินมากๆ&lt;/p&gt;

&lt;p&gt;อ้างอิง&lt;br&gt;
&lt;a href="https://quarkus.io/get-started/"&gt;https://quarkus.io/get-started/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part2&lt;/strong&gt; &lt;a href="https://dev.to/pramoth/erimtn-quarkus-3-part-2-web-4bkm"&gt;https://dev.to/pramoth/erimtn-quarkus-3-part-2-web-4bkm&lt;/a&gt;&lt;/p&gt;

</description>
      <category>quarkus</category>
    </item>
    <item>
      <title>Explicit receiver parameter(this) in Java 8</title>
      <dc:creator>Pramoth Suwanpech</dc:creator>
      <pubDate>Tue, 14 Jun 2022 09:00:20 +0000</pubDate>
      <link>https://dev.to/pramoth/explicit-receiver-parameterthis-in-java-8-2ojk</link>
      <guid>https://dev.to/pramoth/explicit-receiver-parameterthis-in-java-8-2ojk</guid>
      <description>&lt;p&gt;Explicit receiver parameter เป็นฟีเจอร์ที่มาใหม่ตั้งแต่ Java 8 ไม่ค่อยได้ใช้ บางครั้งก็ลืมกันไปเลยว่ามี วันนี้เรามา Note ไว้ซะหน่อย&lt;/p&gt;

&lt;p&gt;ปกติแล้วเวลาเราเรียกเมธอดที่เป็น instance method (ที่ไม่ใช่ static) จาวาคอมไพล์เลอร์จะใส่ implicit receive parameter ที่ตำแหน่ง 0 ที่หมายถึง instance ของ object(แทนด้วย this)&lt;/p&gt;

&lt;p&gt;เช่น ถ้ามีเมธอด &lt;code&gt;int getAge()&lt;/code&gt; เวลาคอมไพล์ออกมาจะได้ &lt;code&gt;getAge(Person p)&lt;/code&gt; เพื่อที่จะได้เรียกเมธอด getAge() ใน context ของ object ใดๆโดยคอมไพเลอร์จัดการให้และไม่ยอมให้เราใส่เอง&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;getAge&lt;/span&gt;&lt;span class="o"&gt;(){..}&lt;/span&gt;

&lt;span class="err"&gt;\\&lt;/span&gt;&lt;span class="n"&gt;คอมไพล์แล้วจะได้แบบนี้นะ&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ใน&lt;/span&gt; &lt;span class="n"&gt;bytecode&lt;/span&gt; &lt;span class="n"&gt;อยู่ลำดับแรกของพารามิเตอร์&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;getAge&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;){...}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;แต่ว่า Java 8 เพิ่มฟีเจอร์ใหม่มาทำให้เราสามารถประกาศเมธอดที่มี receive parameter ได้ (แต่ตอน call method จะระบุไม่ได้เหมือนเดิม)&lt;br&gt;
สาเหตที่เพิ่มมาเพราะเพื่อให้เราเพิ่ม annotation เข้าไปตรง receiver parameter ได้&lt;/p&gt;

&lt;p&gt;โดยเราสามารถ reflection เอา annotaion ได้จาก &lt;code&gt;Method.getAnnotatedReceiverType()&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;getAge&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@MyAnnotation&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setAge&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;App&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setAge&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAge&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ถ้าใครเขียน Python คงนึกออก เพราะเราต้องเวลาประกาศเมธอดก็ต้องมี explicit receiver( self ) เช่นกัน &lt;/p&gt;

&lt;p&gt;ref:: &lt;a href="https://blog.joda.org/2015/12/explicit-receiver-parameters.html"&gt;https://blog.joda.org/2015/12/explicit-receiver-parameters.html&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>OOP in C (data+function+receiver parameter)</title>
      <dc:creator>Pramoth Suwanpech</dc:creator>
      <pubDate>Tue, 14 Jun 2022 04:46:56 +0000</pubDate>
      <link>https://dev.to/pramoth/oop-in-c-datafunctionreceiver-parameter-5b3j</link>
      <guid>https://dev.to/pramoth/oop-in-c-datafunctionreceiver-parameter-5b3j</guid>
      <description>&lt;p&gt;ในบทความนี้จะยกตัวอย่างว่า object ในภาษาอย่าง Java ถูกอิมพลีเมนต์ยังใงถ้าเขียนด้วย C เราจะพูดแค่ตัวแปร this และการเอา function (method) ไปเป็นส่วนหนึ่งของ object เท่านั้น&lt;br&gt;
หวังว่าจะทำให้น้องๆฝึกงานเข้าใจตัวแปร this ในจาวามากขึ้น&lt;br&gt;
สมมติว่ามีคลาสจาวาแบบนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;//Java&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Dog&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setAge&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;getAge&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;concept นึงของ OOP คือการเอา data มารวมกับ function เพื่อให้เกิดเป็น object ที่มีพฤติกรรมและเกิด cohesion สูง&lt;br&gt;
ในภาษา C เราสามารถใช้ struct เป็นส่วน data ของออบเจ็คได้และถ้าหากเราเอา function ใส่ไปใน struct เราก็จะได้ data+behavior เหมือนจาวา&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="c1"&gt;// โครงสร้างข้อมูลที่จำลอง class ในจาวา มี age และ setter/getter&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;setAge&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Dog&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;getAge&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Dog&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;//อิมพลีเมนเตชั่นของเมธอด setAge &lt;/span&gt;
&lt;span class="c1"&gt;//สังเกตุว่าจะมีตัวแปร this เป็นพารามิเตอร์ตัวแรกของเมธอด (เราเรียกตัวแปร this ว่า receiver parameter)  &lt;/span&gt;
&lt;span class="c1"&gt;//ซึ่งในจาวาเราไม่ระบุ receiver parameter แต่ว่า compiler จะเพิ่มให้เราเอง&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setAge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Dog&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// เหมือน setAge มี receiver parameter&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;getAge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Dog&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;//ฟังชั่นที่เอาไว้จำลองการ new Object() ในจาวา เพื่อให้ง่าย จะฟิกค่า new Dog() ไปเลย&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Dog&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;new_operator_for_dog&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
   &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Dog&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Dog&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;malloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="c1"&gt;//เอา function มาเป็นเมธอดของ object ด้วย function pointer&lt;/span&gt;
    &lt;span class="c1"&gt;//เรียกว่าการ binding&lt;/span&gt;
    &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;setAge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;setAge&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;getAge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getAge&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="c1"&gt;//Dog d = new Dog()&lt;/span&gt;
    &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Dog&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new_operator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="c1"&gt;// d.setAge(10)&lt;/span&gt;
    &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;setAge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;//&amp;lt;-- สังเกตว่าเรา explicit receiver parameter เนื่องจากตรงนี้เราจำลองไม่ได้ใน C syntax&lt;/span&gt;
    &lt;span class="c1"&gt;// d.getAge()&lt;/span&gt;
    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;getAge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="c1"&gt;// ใช้เสร็จต้อง free เพราะไม่มี GC&lt;/span&gt;
    &lt;span class="n"&gt;free&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ตัวอย่างที่ชัดเจนอีกภาษาคือ Python ที่เวลาเรียกจะต้องระบุ reveiver parameter&lt;/p&gt;

</description>
    </item>
    <item>
      <title>ทำไมตัวแปร Signed Integer ใช้ 2's complement</title>
      <dc:creator>Pramoth Suwanpech</dc:creator>
      <pubDate>Wed, 08 Jun 2022 02:40:44 +0000</pubDate>
      <link>https://dev.to/pramoth/thamaimtawaepr-signed-integer-aich-2s-complement-3lgk</link>
      <guid>https://dev.to/pramoth/thamaimtawaepr-signed-integer-aich-2s-complement-3lgk</guid>
      <description>&lt;p&gt;ในเลขฐานสิบเราใส่เครื่องหมายลบข้างหน้า เราเป็นมนุษย์เราก็เข้าใจได้ แต่ computer ต้องแปลงทุกสิ่งอย่างเป็นเลขฐานสองก่อน&lt;br&gt;
จึงเกิดคำถามคือ เราจะแปลงเลขฐานสิบ Signed integer ไปเป็นเลขฐานสองอย่างไรดี จึงจะสามารถเอาเลขสองตัว (A และ -B) มาบวกกันแบบเลขฐานสองและสามารถแปลงกลับไปเป็นเลขฐานสิบได้ถูกต้อง โดยที่ไม่ต้องมีลอจิกพิเศษอะไรเพิ่มเติมและ space efficiency(เก็บค่าได้จำนวนมากสุด)&lt;/p&gt;

&lt;p&gt;มีคนคิดหลายวิธี ข้อดีข้อเสียแตกต่างกันไป ผมจะนำเสนอสามวิธีที่มีคนคิดมาแล้ว ดังนี้&lt;/p&gt;
&lt;h3&gt;
  
  
  วิธีที่ 1.
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;เก็บโดยให้มี Signed bit เป็นสัญลักษณ์+-&lt;/strong&gt; ไปเลย (Signed magnitude) เหมือนที่เราใช้ในเลขฐานสิบ โดยให้ Most sinificant bit(MSB) เป็น Sign bit เช่น 3 → 0011b ดังนั้น -3 ก็จะเป็น → &lt;strong&gt;1&lt;/strong&gt;011b &lt;br&gt;
ซึ่งแบบนี้มันดูเข้าใจง่ายสำหรับมนุษย์เลยแหละ แต่มันมีข้อเสีย &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;มันมีศูนย์สองตัวคือ +0 และ -0 (0000b →+0 และ 1000b → -0)&lt;/li&gt;
&lt;li&gt;3+(-3) = 0 ใช่ไหม ไหนเราลองบวกมันหน่อยซิ
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0011b  (3)
     +
1011b  (-3)
1110b ?? 3+(-3) = -5 แทนที่จะเป็น 0 ดังนั้นวิธีนี้ไม่เหมาะแล้ว
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  วิธีที่ 2.
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1's complement&lt;/strong&gt;&lt;br&gt;
   ในวิธีที่ 1 เลขลบและเลขบวกเราแค่กลับบิตแรก(MSB) ส่วนวิธีนี้ให้กลับทุกบิต เช่น &lt;strong&gt;3 --&amp;gt; 0011b&lt;/strong&gt; ดังนั้น &lt;strong&gt;-3 --&amp;gt; 1100b&lt;/strong&gt; จะสังเกตว่าบิตแรกถ้าเป็น 1 จะหมายถึงจำนวนลบเหมือนกับวิธีที่ 1 งั้นเราลองมาบวกกัน&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0001b  (1)
     +
1100b  (-3)
1101b // 1+(-3) = -2 
-------------------------

0010b  (2)
     +
1100b  (-3)
1110b // 2+(-3) = -1
-------------------------

0011b   (3)
     +
1100b   (-3)
1111b // 3+(-3) = -0 

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เราสรุปได้ว่า&lt;br&gt;
1101b = -2&lt;br&gt;
1110b = -1&lt;br&gt;
1111b = -0&lt;/p&gt;

&lt;p&gt;ด้วยวิธีนี้ เราสามารถบวกลบเลขได้ปกติ เพียงแต่ว่ายังเหลือ 1 ปัญหาคือ ยังมี -0 อยู่(1111b)&lt;/p&gt;
&lt;h3&gt;
  
  
  วิธีที่ 3.
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;2's complement&lt;/strong&gt;&lt;br&gt;
   วิธีที่ 2 เกือบดี เหลือปัญหาอีกข้อเดียว คือ -0 ซึ่งมันไม่ make sense ที่จะมี -0 ซึ่งทำให้เราเก็บค่าได้น้อยลง 1 ตัวด้วย &lt;br&gt;
วิธีนี้แก้ไขได้ด้วยการเอา 1 มาบวกเข้าไปกับ 1's complement ดังนั้น &lt;strong&gt;-3 จะเป็น (1100+1) =&amp;gt; 1101b&lt;/strong&gt; &lt;br&gt;
เราลองมาพิศูจน์กันว่า -0 จะหายไปรึป่าว&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0001b   (1)
     +
1101b   (-3)
1110b // 1+(-3) = -2 
-------------------------

0010b   (2)
     +
1101b   (-3)
1111b // 2+(-3) = -1
-------------------------

0011b    (3)
     +
1101b    (-3)
0000b // Yes !! 3+(-3) = 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เราสรุปได้ว่า&lt;br&gt;
1110b = -2&lt;br&gt;
1111b = -1&lt;br&gt;
0000b =  0&lt;/p&gt;

&lt;p&gt;จะเห็นว่า 2's complement perfect สุด &lt;br&gt;
ดังนั้นตัวแปรที่เป็นเลขบวกและลบ(Signed) จึงจะถูกเก็บในรูปแบบ 2'complement นั่นเอง&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Spring Boot executable jar ทำงานยังไง</title>
      <dc:creator>Pramoth Suwanpech</dc:creator>
      <pubDate>Sat, 29 Aug 2020 09:24:48 +0000</pubDate>
      <link>https://dev.to/pramoth/spring-boot-executable-jar-1ca0</link>
      <guid>https://dev.to/pramoth/spring-boot-executable-jar-1ca0</guid>
      <description>&lt;p&gt;ใน Linux เราสามารถรันโปรแกรมแบบนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-al&lt;/span&gt; &lt;span class="c"&gt;#lookup ls in PATH&lt;/span&gt;
./myprgram &lt;span class="c"&gt;# รัน myprogram ที่อยู่ใน current directory&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ทราบกันไหมครับว่าเราสามารถรัน spring boot jar เหมือนที่เรารันโปรแกรมในshell ได้แบบเดียวกันด้วย ถ้าเรา config spring-boot-maven-plugin &lt;code&gt;executable=true&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./myjar.jar 
&lt;span class="c"&gt;#เราใส่ . ไปเพราะว่า Linux ไม่ได้เพิ่ม working directory เข้าไปใน PATH เหมือน Windows&lt;/span&gt;
&lt;span class="c"&gt;# เราจึงต้องระบุพาธ(relative path)ของไฟล์ที่จะรันเอง&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ปกติแล้ว เราจะไม่สามารถรัน .jar ไฟล์แบบนี้ได้ เพราะ jar ไม่ใช่ shell script หรือโปรแกรม แต่มันคือ archive ไฟล์ (zip format) &lt;strong&gt;&lt;em&gt;แล้วมันรันแบบนั้นได้ยังไง!!!&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# ปกติเรารัน jar ที่มี main-class ระบุใน manifest แบบนี้&lt;/span&gt;
java &lt;span class="nt"&gt;-jar&lt;/span&gt; myjar.jar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;คำตอบก็คือ ใน Linux เราสามารถเพิ่ม binary file (ในที่นี้คือ jar) เข้าไปต่อท้าย shell script ได้ ทำให้เรารวม script &lt;code&gt;java -jar myjar.jar&lt;/code&gt; กับ jar ไฟล์เข้าด้วยกันได้ และยังสามารถ execute script ได้ด้วย&lt;/p&gt;

&lt;p&gt;ตัวอย่างวิธีการทำคร่าวๆ&lt;br&gt;
เตรียมไฟล์ shell script สำหรับรัน java -jar&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;
&lt;span class="nb"&gt;exec &lt;/span&gt;java  &lt;span class="nt"&gt;-jar&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="c"&gt;# $@ คือ all parameter ที่เราส่งมา ยกเว้นตัวที่ 0 ($0 คือชื่อไฟล์)&lt;/span&gt;
&lt;span class="nb"&gt;exit &lt;/span&gt;0
&lt;span class="c"&gt;#ไฟล์ run.sh&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จากนั้น เอา jar file มาต่อท้าย shell script&lt;br&gt;
&lt;code&gt;cat run.sh myjar.original.jar &amp;gt; myjar.jar&lt;/code&gt;&lt;br&gt;
change mode myjar.jar ให้สามารถ execute ได้&lt;br&gt;
&lt;code&gt;chmod +x myjar.jar&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;ทดลองรัน&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;❯ ./myjar.jar
Hello World
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ลองดูใน content ของ myjar.jar&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;xxd &lt;span class="nt"&gt;-l&lt;/span&gt; 100 myjar.jar
00000000: 2321 2f62 696e 2f73 680a 6578 6563 206a  &lt;span class="c"&gt;#!/bin/sh.exec j&lt;/span&gt;
00000010: 6176 6120 202d 6a61 7220 2224 3022 2020  ava  &lt;span class="nt"&gt;-jar&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
00000020: 2224 4022 0a65 7869 7420 300a 504b 0304  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;.exit 0.PK..
00000030: 1400 0808 0800 2c79 1c51 0000 0000 0000  ......,y.Q......
00000040: 0000 0000 0000 0900 0400 4d45 5441 2d49  ..........META-I
00000050: 4e46 2ffe ca00 0003 0050 4b07 0800 0000  NF/......PK.....
00000060: 0002 0000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Note.
&lt;/h3&gt;

&lt;p&gt;นอกจากเราจะรันมันด้วย shell แล้ว เรายังสามารถรันมันด้วย java -jar myjar.jar เหมือนปกติได้ด้วย (อันนี้ผมเข้าใจว่าเป็นความสามารถของ java เอาที่สามารถ skip content  อื่นๆไปจนกว่าจะเจอ jar header ถึงทำการ parse)&lt;/p&gt;

&lt;p&gt;ใครอยากลองทำเล่นก็ clone git &lt;a href="https://github.com/pramoth/executable-jar"&gt;https://github.com/pramoth/executable-jar&lt;/a&gt; มาเล่นได้เลยครับ&lt;/p&gt;

&lt;p&gt;ส่วน spring boot จะใช้ script นี้ &lt;a href="https://github.com/spring-projects/spring-boot/blob/2.3.x/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/resources/org/springframework/boot/loader/tools/launch.script"&gt;https://github.com/spring-projects/spring-boot/blob/2.3.x/spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/resources/org/springframework/boot/loader/tools/launch.script&lt;/a&gt;&lt;br&gt;
โดย spring-boot-maven-plugin เป็นคนเอาไปรวมกับ jar &lt;/p&gt;

&lt;p&gt;อ้างอิง&lt;br&gt;
&lt;a href="https://coderwall.com/p/ssuaxa/how-to-make-a-jar-file-linux-executable"&gt;https://coderwall.com/p/ssuaxa/how-to-make-a-jar-file-linux-executable&lt;/a&gt;&lt;/p&gt;

</description>
      <category>shellscript</category>
    </item>
    <item>
      <title>[Spring Data JPA] native query no converter for TimeStamp --&gt; LocalDate!!</title>
      <dc:creator>Pramoth Suwanpech</dc:creator>
      <pubDate>Sat, 25 Apr 2020 12:39:06 +0000</pubDate>
      <link>https://dev.to/pramoth/spring-data-jpa-native-query-no-converter-for-timestamp-localdate-41dh</link>
      <guid>https://dev.to/pramoth/spring-data-jpa-native-query-no-converter-for-timestamp-localdate-41dh</guid>
      <description>&lt;p&gt;ถ้าหากเราใช้ Spring Data JPA native query และใช้ projection interface ที่แมป column java.sql.TimeStamp ไปเป็น LocalDate จะไม่สามารถทำได้ เนื่องจาก default converter ไม่มีมาให้ (ถ้าเป็น LocalDateTime มีให้นะครับ)&lt;/p&gt;

&lt;p&gt;นอกจากไม่มีมาให้แล้ว error message ที่พ่นออกมาตอนเกิด exception ก็ไม่สื่ออ่านแล้วอาจเข้าใจผิดได้ มันออกมาว่า &lt;code&gt;Projection type must be an interface!&lt;/code&gt; ซึ่งไม่ใช่&lt;/p&gt;

&lt;p&gt;วิธีแก้ปัญหาคือ เราต้อง custom &lt;code&gt;Converter&amp;lt;Timestamp, LocalDate&amp;gt;&lt;/code&gt; เอา แต่ว่า ตอนรีจิสเตอร์ custom converter นี่แหละ จะรีจิสเตอร์ธรรมดาไม่ได้&lt;/p&gt;

&lt;p&gt;ถ้าเราทำให้ converter เป็น @Bean หรือ register ผ่าน FormatterRegistry.addConverter() ใน WebMvcConfigurer จะยังไม่ทำให้ Spring Data JPA หยิบ converter ที่เพิ่มเข้าไปมาใช้!!!! เพราะว่า Spring Data Jpa ไม่ได้ใช้ ConversionService  ตัวที่มัน default มาให้กับ Spring Boot แต่มันใช้ &lt;code&gt;DefaultConversionService.getSharedInstance()&lt;/code&gt; ดังนั้น จะให้มันทำงานได้จะต้องมารีจีสเตอร์ที่ตรงนี้ (วางโค๊ดไว้ใหนสักที่ ที่เป็น initialization method เพราะ เป็น static singleton instance ธรรมดา)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="nc"&gt;DefaultConversionService&lt;/span&gt; &lt;span class="n"&gt;conversionService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;DefaultConversionService&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;DefaultConversionService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getSharedInstance&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;conversionService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addConverter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TimeStampToLocalDateConverter&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;โค๊ดด้านล่างนี้หยิบมาจากใน Spring Data Jpa ตรงส่วนที่ใช้ ConversionService&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;        &lt;span class="cm"&gt;/**
         * Creates a new {@link ProjectingConverter} for the given {@link ReturnedType} and {@link ProjectionFactory}.
         *
         * @param type must not be {@literal null}.
         * @param factory must not be {@literal null}.
         */&lt;/span&gt;
        &lt;span class="nc"&gt;ProjectingConverter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ReturnedType&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ProjectionFactory&lt;/span&gt; &lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;DefaultConversionService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getSharedInstance&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;จะเห็นว่ามันใช้ &lt;code&gt;DefaultConversionService.getSharedInstance()&lt;/code&gt; โดยตรง&lt;/p&gt;

</description>
      <category>springdatajpa</category>
    </item>
    <item>
      <title> Java InvokeDynamic (part 4 Lambda expression)</title>
      <dc:creator>Pramoth Suwanpech</dc:creator>
      <pubDate>Fri, 03 Apr 2020 15:27:04 +0000</pubDate>
      <link>https://dev.to/pramoth/java-invokedynamic-part-4-lambda-expression-2f2p</link>
      <guid>https://dev.to/pramoth/java-invokedynamic-part-4-lambda-expression-2f2p</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;ตอนนี้ใช้พื้นฐานจาก part ก่อนหน้านี้นะครับ&lt;br&gt;
&lt;a href="https://dev.to/pramoth/java-invokedynamic-part-3-bytecode-36jk"&gt;อ่าน part 3 invokedynamic bytecode จากที่นี่&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;ในตอนนี้นี้จะอธิบายในส่วนของ lambda express ซึ่งมีในจาวา 8 ขึ้นไป โดยตัว lambda expression นี้จะอิมพรีเมนต์แตกต่างกับ annonymouse innter class ออกไป&lt;/p&gt;

&lt;p&gt;lambda expression ในจาวา 8 ส่วนหนึ่งจะใช้ฟีเจอร์ที่มีเข้ามาตั้งแต่ในจาวา 7 นั่นก็คือ invokedynamic ซึ่งถูกออกแบบมาให้รองรับกับพวกภาษาไดนามิคที่รันบน JVM อย่างพวก JRuby,Groovy เพื่อให้ resolve target method ที่จะถูกเรียกได้ตอนรันไทม์ (เดิมทีถ้าเราจะทำแบบนี้จะต้องใช้ Reflection)&lt;/p&gt;

&lt;p&gt;ผมจะขอยกตัวอย่างจากโค๊ดให้ดูเลยนะครับ ให้โฟกัสที่ &lt;code&gt;test()&lt;/code&gt; นะครับ&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LambdaTest&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// 1. Not refer to outer scope&lt;/span&gt;
        &lt;span class="c1"&gt;// javac will create a synthetic static  method  name "lambda$test$0()"&lt;/span&gt;
        &lt;span class="nc"&gt;Runnable&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello From Lambda. no capture variable"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// 2. Refer/capture value from outer scope&lt;/span&gt;
        &lt;span class="c1"&gt;// javac will create a synthetic static method name "lambda$test$1(java.lang.String)V"&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Pramoth"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="nc"&gt;Runnable&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello From Lambda "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" with capture variable"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;


    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Throwable&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// จำลอง invokedynamic ไปที่ bootstrap `lambda$test$0`&lt;/span&gt;
        &lt;span class="nc"&gt;Runnable&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mimic_call_lambda$test&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="c1"&gt;// print "Hello From Lambda. no capture variable"&lt;/span&gt;
        &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// จำลอง invokedynamic ไปที่ bootstrap `lambda$test$1`&lt;/span&gt;
        &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mimic_call_lambda$test&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Pramoth"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// print "Hello From Lambda Pramoth with capture variable"&lt;/span&gt;
        &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;Runnable&lt;/span&gt; &lt;span class="n"&gt;mimic_call_lambda$test&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Throwable&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// LambdaMetafactory จะทำการ implement Runnable.run ด้วยการทำ bytecode manipulation โดย ASM ดูการทำงานใน  java.lang.invoke.InnerClassLambdaMetafactory&lt;/span&gt;
        &lt;span class="nc"&gt;CallSite&lt;/span&gt; &lt;span class="n"&gt;lambda$test$CallSite&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LambdaMetafactory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;metafactory&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MethodHandles&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lookup&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
                &lt;span class="s"&gt;"run"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// method ที่จะ  implement คือ Runnable.run()&lt;/span&gt;
                &lt;span class="nc"&gt;MethodType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;methodType&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Runnable&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;// method type ของ factory method จะรีเทริน Runnable อารมณ์คล้ายๆ Runnable Factory.create()&lt;/span&gt;
                &lt;span class="nc"&gt;MethodType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;methodType&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;// อิมพลีเมนต์เมธอดจะรีเทร์น void `public void run()`&lt;/span&gt;
                &lt;span class="nc"&gt;MethodHandles&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lookup&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;findStatic&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LambdaTest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"lambda$test$0"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;MethodType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;methodType&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)),&lt;/span&gt; &lt;span class="c1"&gt;// MethodHandle ที่เอาไว้เรียกเมธอดที่ javac สร้างมาเป็น body ของ lambda&lt;/span&gt;
                &lt;span class="nc"&gt;MethodType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;methodType&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// อิมพลีเมนต์เมธอดจะรีเทร์น void `public void run()` อันนี้ที่เพราะสามารถรีเทริน more specific class ได้ กรณีนี้ ไม่ได้ใช้ก็ระบุ void.class เหมือนรีเทรินของอิมพลีเมนต์เมธอด&lt;/span&gt;
        &lt;span class="c1"&gt;// invoke โดยไม่มี capture vairable&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Runnable&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;lambda$test$CallSite&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;dynamicInvoker&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;invokeExact&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;Runnable&lt;/span&gt; &lt;span class="n"&gt;mimic_call_lambda$test&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;captureVariable&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Throwable&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;CallSite&lt;/span&gt; &lt;span class="n"&gt;lambda$test$CallSite&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LambdaMetafactory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;metafactory&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MethodHandles&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lookup&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
                &lt;span class="s"&gt;"run"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="nc"&gt;MethodType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;methodType&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Runnable&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;// method type ของ factory method จะรีเทริน Runnable แต่ว่าเคสนี้มีการ capture variable ด้วย ดังนั้นจึงต้องระบุ parameter ด้วย อารมณ์คล้ายๆ Runnable Factory.create(String)&lt;/span&gt;
                &lt;span class="nc"&gt;MethodType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;methodType&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
                &lt;span class="nc"&gt;MethodHandles&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lookup&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;findStatic&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;LambdaTest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"lambda$test$1"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;MethodType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;methodType&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)),&lt;/span&gt;
                &lt;span class="nc"&gt;MethodType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;methodType&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
        &lt;span class="c1"&gt;// invoke พร้อมกับ capture vairable&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Runnable&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;lambda$test$CallSite&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;dynamicInvoker&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;invokeExact&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;captureVariable&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;javac จะเปลี่ยน body ของ lambda expression ไปเป็น &lt;code&gt;target method&lt;/code&gt; ที่มีชื่อ &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;private static R &lt;code&gt;lambda$(method)$x&lt;/code&gt; ในกรณีอยู่ใน method&lt;/li&gt;
&lt;li&gt;private static R &lt;code&gt;lambda$new$x&lt;/code&gt; ในกรณีอยู่ใน instance initializer block หรือตรง initial ค่าของ instance variable&lt;/li&gt;
&lt;li&gt;private static R &lt;code&gt;lambda$static$x&lt;/code&gt; ในกรณีอยู่ใน static initializer block หรือตรง initial ค่าของ class variable
โดย x จะเป็น 0 1 2 .... และ R คือ return type&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;เมธอดที่สร้างขึ้นจะมีแอททริบิว ACC_SYNTHETIC ซึ่งหมายถึง compiler เป็นผู้สร้างให้&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;จากนั้น javac จะสร้าง CONST_MethodHandle_info ใน bytecode เพื่อให้ invokedynamic เรียกใช้งาน โดยในภาษาจะมี api ที่เป็น generic &lt;code&gt;bootstrap method&lt;/code&gt; ที่ใช้สำหรับอิมพลีเมนต์ functional interface อยู่ ซึ่งก็คือคลาส java.lang.invoke.LambdaMetafactory&lt;/p&gt;

&lt;p&gt;เมื่อ &lt;code&gt;invokedynamic&lt;/code&gt; ทำงานจะไปเรียก &lt;code&gt;bootstrap method&lt;/code&gt; java.lang.invoke.LambdaMetafactory.metafactory() เพื่อสร้าง CallSite ที่เมื่อเรียก invoke*() จะรีเทริน implementation ของ &lt;code&gt;functional interface&lt;/code&gt; นั้นๆ ซึ่งตัว implementation นี้จะอิมพลีเมนต์ &lt;code&gt;functional method&lt;/code&gt; ด้วยการไปเรียก MethodHandle ของ &lt;code&gt;target method&lt;/code&gt; อีกที (อธิบายไว้ในโคีดนะครับ)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;อันนี้เป็น internal representation นะครับ ไม่ควรเอาไปเรียกใช้ตรงๆอย่างในโค๊ด อันนี้แค่เดโม&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;โดยผมยกตัวอย่างไว้ 2 กรณี&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;กรณีที่ lambda expression ไม่ได้อ้างถึงตัวแปรใน outer scope
(ตัวอย่างการเรียกใช้งานในเมธอด &lt;code&gt;mimic_call_lambda$test$0()&lt;/code&gt;)
&lt;code&gt;target method&lt;/code&gt; ที่ได้จะออกมาเป็น
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;lambda$test&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;กรณีที่ lambda expression อ้างถึงตัวแปรใน outer scope (ตัวอย่างการเรียกใช้งานในเมธอด &lt;code&gt;mimic_call_lambda$test$1(String captureVariable)&lt;/code&gt;)
&lt;code&gt;target method&lt;/code&gt; ที่ได้จะออกมาเป็น
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;lambda$test&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lang&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;String&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;จะสังเกตว่าจะมีการรับค่าที่ capture มาจาก outer scope มาด้วย&lt;/p&gt;

&lt;p&gt;ตัวอย่าง bytecode ที่ javac สร้างมาให้นะครับ&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private static void lambda$test$1();
    descriptor: ()V
    flags: ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
    Code:
      stack=2, locals=0, args_size=0
         0: getstatic     #18                 // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #26                 // String Hello From Lambda. no capture variable
         5: invokevirtual #25                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return
      LineNumberTable:
        line 15: 0

  private static void lambda$new$0();
    descriptor: ()V
    flags: ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
    Code:
      stack=2, locals=0, args_size=0
         0: getstatic     #18                 // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #27                 // String dd
         5: invokevirtual #25                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return
      LineNumberTable:
        line 9: 0
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;จบแล้วครับสำหรับ invokedynamic หรือ Indy!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;สำหรับใครที่อยากรู้ว่า javac อิมพรีเมนต์ annonymous inner class อย่าไร รวมถึงวิธีการที่มัน cature variable จาก outer scope&lt;br&gt;
&lt;a href="https://medium.com/@pramothsuwanpech/%E0%B8%88%E0%B8%B2%E0%B8%A7%E0%B8%B2%E0%B8%84%E0%B8%AD%E0%B8%A1%E0%B9%84%E0%B8%9E%E0%B8%A5%E0%B9%8C%E0%B9%80%E0%B8%A5%E0%B8%AD%E0%B8%A3%E0%B9%8C%E0%B8%AD%E0%B8%B4%E0%B8%A1%E0%B8%9E%E0%B8%A3%E0%B8%B5%E0%B9%80%E0%B8%A1%E0%B8%99%E0%B8%95%E0%B9%8C-closure-%E0%B8%AD%E0%B8%A2%E0%B9%88%E0%B8%B2%E0%B8%87%E0%B9%84%E0%B8%A3-f1b98d951de4"&gt;อ่านได้จากที่นี่&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://github.com/pramoth/invokedynamic"&gt;source code&lt;/a&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>lambda</category>
    </item>
  </channel>
</rss>
