Javaやさんに優しいローコードフレームワーク、OpenXavaを試す

OpenXavaという、JPAエンティティだけ定義すればCRUDな画面を作ってくれるローコードフレームワークがあるので、試してみました。
Javaわかる人には手軽に使えてよさそう。
https://www.openxava.org/

OpenXavaプロジェクトの作成

Maven Archetypeが用意されているので、こんな感じのMavenコマンドで始めれます。

mvn archetype:generate -DarchetypeGroupId=org.openxava -DarchetypeArtifactId=openxava-archetype -DarchetypeVersion=RELEASE -DgroupId=com.yourcompany -DartifactId=invoicing -DinteractiveMode=false

しかし、Mavenコマンドを入力するのはめんどいので、IDEを使いましょう。
NetBeansだとProject from Archetypeを選ぶとArchetype指定でプロジェクトが作成できます。

そしたらSearchにxavaといれればopenxava-archetypeが出てきます。

IntelliJ IDEAの場合はCatalogにMaven Centralを指定すると、Archetypeにxavaを入力すれば候補が出てきます。

プロジェクトのファイル構成はこんな感じ

modelのYourFirstEntity.javaはこんな感じです。

@Entity @Getter @Setter
public class YourFirstEntity extends Identifiable {
    
    @Column(length=50) @Required
    String description;
    
    LocalDate date;
    
    BigDecimal amount;

}

そしてrunのxavaSample.javaはこんな感じ。

public class xavaSample {

    public static void main(String[] args) throws Exception {
        DBServer.start("xavaSample-db"); 
        AppServer.run("xavaSample"); 
    }

}

起動

プロジェクトをビルドしてこのxavaSample.javaを実行するとTomcatが起動します。
ログの最後にアクセスURLが表示されます。

アクセスするとこんな画面が。

サインインに行くとログイン画面がでます。admin / adminでログイン。ただし、enterキーではログインできないので、「サインイン」ボタンをクリックする必要があります。めんどい。

「左がわのモジュールを選べ」とでかい矢印が出てます。ウィンドウ幅が狭いと左のバーが出てないので、ウィンドウを広げましょう。

「Your first entity」を選ぶと、データ入力フォームが出るので、適当に入力して「保存」

「リスト」を選ぶとデータが入ってます。

右上のグラフボタンを選ぶとグラフが。横軸に日付を選んでいます。

カレンダーも。

詳細付データを登録してみる

注文-注文詳細なデータを登録してみます。
こんな感じ。

エンティティはこんな感じを。

まずカテゴリ。

package naoki.xavasample.xavaSample.model;

import javax.persistence.*;
import org.openxava.annotations.Required;
import lombok.*;

@Entity @Setter @Getter
public class Category {
    @Id
    long id;
    
    @Required
    String name;
}

それから注文詳細。注文に埋め込むので@Embeddableにしています。
@DescriptionsListをつけるとドロップダウンにしてくれるらしい。

package naoki.xavasample.xavaSample.model;

import javax.persistence.*;
import org.openxava.annotations.DescriptionsList;
import lombok.*;

@Embeddable @Setter @Getter
public class OrderDetail {
    
    String name;

    @ManyToOne(fetch = FetchType.LAZY, optional = true)
    @DescriptionsList
    Category category;

    long price;
}

そして注文。ここでOrderにしてしばらくハマっていた。SQLのキーワードは避けましょう。
主キーをUUIDにするためにいろいろついています。
あと、@DefaultValueCalculatorで初期値を設定してくれる。
それから、詳細部分は@ElementCollectionにして、表示項目を@ListPropertiesで指定しています。

package naoki.xavasample.xavaSample.model;

import java.time.LocalDate;
import java.util.Collection;
import javax.persistence.*;

import org.hibernate.annotations.GenericGenerator;
import org.openxava.annotations.DefaultValueCalculator;
import org.openxava.annotations.Hidden;
import org.openxava.annotations.ListProperties;
import org.openxava.annotations.Required;
import org.openxava.calculators.CurrentLocalDateCalculator;

import lombok.*;

@Entity @Setter @Getter
public class Orders {
    @Id
    @GeneratedValue(generator="system-uuid")
    @Hidden
    @GenericGenerator(name="system-uuid", strategy="uuid")
    @Column(length=32)
    String oid;
   
    @Required
    @DefaultValueCalculator(CurrentLocalDateCalculator.class)
    LocalDate orderDate;
    
    String customerName;
    
    @ElementCollection
    @ListProperties("name, price, category")
    Collection<OrderDetail> details;
}

そうすると、こういう登録画面が。

一覧からはみ出た[+]ボタンを押すとカテゴリが追加できます。
これ、category - priceの順にすると、ボタンがpriceのところにかぶってダメな感じでした。

ということでカテゴリーも選べるようになっています。

テーブルはこんな感じになっています。

ついでに、下部のテーマからBlueを選んでみます。

いい感じ。これデフォルトにすればいいのに。

データベースを変更する

MySQLPostgreSQLなど外部DBを使うときはsrc/main/webapp/META-INF/context.xmlを編集します。
こんな感じで設定がコメントで書いてあるので、必要なものを有効にします。

 <!-- HSQLDB -->       
    <Resource name="jdbc/myXavaDS" auth="Container" type="javax.sql.DataSource"
          maxTotal="20" maxIdle="5" maxWaitMillis="10000"
          username="sa" password="" 
          driverClassName="org.hsqldb.jdbc.JDBCDriver"
          url="jdbc:hsqldb:hsql://localhost:1666"/>
          
    <!-- MySQL       
    <Resource name="jdbc/myXavaDS" auth="Container" type="javax.sql.DataSource"
         maxTotal="20" maxIdle="5" maxWaitMillis="10000"
         username="root" password="" 
         driverClassName="com.mysql.cj.jdbc.Driver"
         url="jdbc:mysql://localhost:3306/myXavadb"/>       
   -->      
    
    <!-- PostgreSQL 
   <Resource name="jdbc/myXavaDS" auth="Container" type="javax.sql.DataSource"
         maxTotal="20" maxIdle="5" maxWaitMillis="10000"
         username="postgres" password=""
         driverClassName="org.postgresql.Driver" 
         url="jdbc:postgresql://localhost/myXavadb"/>
   -->

JDBCドライバはdependencyに含める必要があります。
それもpom.xmlにコメントで書いてあるので、必要なものを有効にします。

<!-- 
To access to your database uncomment the corresponding entry 
from the below dependencies. If you don't find yours, look in
internet for the maven depencency for your database and add it 
here yourself.
-->

<!-- MySQL 
<dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>      
<version>8.0.32</version>
</dependency>
-->

<!-- PostgreSQL 
<dependency>
        <groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.5.4</version>
</dependency>
-->

あと、mainメソッドのDB起動部分はコメントアウトします。

// DBServer.start("xavaSample-db"); 
AppServer.run("xavaSample"); 

まとめ

なんかデータ管理するだけであれば結構便利。
権限管理が必要になると有償版を使うことになるけど、手元のデータを管理するくらいだと十分じゃなかろうか。

Stable Diffusion Web UIの解像度をSDXLにあわせたドロップダウンにする

Stable Diffusionの新しいバージョン、SDXLが出ています。
ただ、SDXLは大きい画像で学習しているためか、ちゃんとした画像を生成するにはそれなりの解像度を設定する必要があります。
ということで、Stable Diffusion Web UIの解像度設定をスライダーからドロップダウンにしてよさげな値を指定しやすくしてみました。

SDXLでは512x512で画像を生成すると、こういうパターンが生成されることが多くなります。

まともなものが生成されても、ちょっと画力低くないですかと言いたくなるものになってしまいます。

ということで、SDXLを使うときのオススメ解像度がいくつか出てきていますね。

https://www.reddit.com/r/StableDiffusion/comments/15c3rf6/sdxl_resolution_cheat_sheet/

アニメ画風のファインチューンモデル、Animagine XLでは次のような解像度がオススメされています。
https://huggingface.co/Linaqruf/animagine-xl

それで1344x768で生成されたのがこちら。SDXLらしさ!

プロンプトはこんな感じ

positive
twin tail, library, face focus, cute, masterpiece, best quality, 1girl, looking at viewer, upper body

negative
lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry

ただ、この解像度を覚えて指定するのが割と面倒ですね。
ということでStable Diffusion Web UIの解像度指定をドロップダウンに変更してみます。
modules/ui.py の442行目

width = gr.Slider(minimum=64, maximum=2048, step=8, label="Width", value=512, elem_id="txt2img_width")
height = gr.Slider(minimum=64, maximum=2048, step=8, label="Height", value=512, elem_id="txt2img_height")

↓ SliderをDropdownに。

width = gr.Dropdown(label = "Width", elem_id="txt2img_width", value="512", allow_custom_value=True, choices = [448,512,768,886,915,1024,1144,1182,1254,1344,1354,1564])
height = gr.Dropdown(label = "Height", elem_id="txt2img_height", value="512", allow_custom_value=True, choices = [448,512,768,886,915,1024,1144,1182,1254,1344,1354,1564])

ただ、そうすると解像度が文字列で渡ってしまってエラーになるので、intへ変換

modules/txt2img.py の33行目を修正

width=width,
height=height,

↓ intをつけます

width=int(width),
height=int(height),

これで指定がドロップダウンになります。

MetaのMusicGenに90年代コムロJ-POPを作ってもらう

Metaがテキストから音楽や音声を生成するAIを公開していました。 https://audiocraft.metademolab.com/

AudioGenが効果音とかを生成、MusicGenが音楽を生成ですね。

「90s J-POP like Komuro」というプロンプトで、それっぽい音楽をつくってくれました。

512トークンで10秒になります。MediumでGPU(RTX 4060 Ti)つかって生成に30秒くらいかな。 CPU(7世代i7)だとSmallで256トークンが80秒くらい。

Transformersの4.31.0に含まれているので、PyTorchとTransformersを導入すれば使えるはず。あとffmpegにパスを通す必要があります。

モデルの準備はこんな感じ。

from transformers import AutoProcessor, MusicgenForConditionalGeneration

model_name = "facebook/musicgen-medium"

processor = AutoProcessor.from_pretrained(model_name)
model = MusicgenForConditionalGeneration.from_pretrained(model_name).to("cuda")

モデルにはsmall, medium, largeがあります。音質がよくなる。 CPUで動かすときは"cuda""cpu"にします。

そして生成

text = "90s J-POP like Komuro"
inputs = processor(
  text=text,
  padding=True,
  return_tensors="pt",
).to(model.device)
audio_values = model.generate(**inputs, max_new_tokens=token_count)

あとはファイルに保存。

import scipy
sampling_rate = model.config.audio_encoder.sampling_rate
scipy.io.wavfile.write("musicgen.wav", rate=sampling_rate, data=audio_values.cpu().numpy())

GradioのUIを作ったソースはこちら
https://gist.github.com/kishida/10ca95df2b6566c0acfdbcd59dde2abd

コミュニティノートがTwitterを壊している

コミュニティノート、案の定暴走している。
どんな改悪、利用制限よりも大きくTwitter*1を壊してるんじゃなかろうか。

コミュニティノートは、多数派に有利な仕組みです。 「コミュニティノートでは、さまざまな視点を持つユーザーにとって役に立つノートが特定されます」 となっていますが、多数派であればさまざまな視点を持つユーザーが確保しやすく、逆に少数派は視点が収束する傾向があるので不利になります。

そのため、なんらかの不満をもっているけどその不満を表明して言葉にするとだいたい間違っているという層には非常に居づらくなっています。

「間違ったツイートをしなければいい」のような発言をみかけるけど、裏を返せば「間違ったツイートをしたならばなにをされても仕方ない」ということにもなっていて、正義であればなにをしても許されるというような「正義の暴走」になっているように見えます。 特に間違っていないのに、単に反対意見の表明がついていることもありますが、多数派にとって心地いいのでそのまま掲載されたりします。
嫌われ者が叩かれているのをみて留飲をさげるような人にとってはいい機能かもしれないけど、それもまた正義が暴走しています。

そうすると、そういった少数派はTwitterから離れて、ThreadsやBlue Skyなど対抗SNSに移行していくと思います。そんな感じで、分断が強くなるんではないかと。

そして、こういったリプライで十分な情報にもコミュニティノートがついていたりします。役にたつかもしれないけど、ツイートの面白さは失われています。

コミュニティノートは、つけられた側からすると間違いや無知がさらされツイートの価値を貶めるものになってしまっています。コントロールもできずツイートを訂正できるわけでもないので、うれしくない。
そして、見る側からも特にうれしくないものも増えています。
一方で、コミュニティノートを書く側としては、自分の文章が有名ツイートにぶらさがって、そしてほとんどの場合はツイートよりも面積をとって目立つようになり、多くの人が話題にするので、自己顕示欲がみたされます。
いままで見たなかで、手軽に最も承認欲求が満たされるツールになっているように思います。YouTubeで炎上動画をとっても、他の人が同じようなことをすると埋もれていきますが、コミュニティノートは有名ツイートにのっかる形なので埋もれることはありません。 おそらく、コミュニティノート承認欲求お化けのような人を生産してるはず。

少数派がTwitterから離れるというのをみて、「嫌われ者は出ていけばええんや」みたいなことを思った人がいるかもしれませんが、コミュニティノートというハンマーを手にした承認欲求お化けにとってすべてのツイートは釘に見えるようになっているので、その時点での少数派に矛先が向かっていくのではないかと思います。

あと、コミュニティノートはある程度バズらないと対象にならないので、有名人ほどノートがつきやすいのだけど、つまり有名人ほどコミュニティノートに嫌気さして抜けていく確率が高くなってしまう。
有名人いなくなれば、それを目当てに入ってくる人もいなくなるので、代謝も悪くなっていく。

こうやってTwitterが本格的に壊れる未来がみえてしまった・・・

こういう話は伝わらない人には伝わらないと思うけど、とりあえず倫理学の入門書をおいておきます。

*1:TwitterだったサービスをそのままTwitterと表記します

  • はげ

    素直にミスキーに行け
    バカにされるから

  • aa

    腹が立ちましたか?

  • any

    嘘が訂正されるシステムが必要無いというのは、
    ネットの発言に対して、嘘を振りまいても責任を取る気が無いと?

  • もっと読む
コメントを書く

rinnaの画像対話モデルをUIで試す。あとGradioの練習。

おうちで日本語で画像を使った会話ができるようになりましたよ、ということで、試してみます。

rinna 画像対話モデル

おとといrinnaから日英バイリンガルモデルが発表されました。
rinna、日英バイリンガル大規模言語モデルをオープンソースで公開|rinna株式会社

このモデルには画像対話モデルも含まれています。つまり、画像についてrinnaとチャットができるようになっています。
https://huggingface.co/rinna/bilingual-gpt-neox-4b-minigpt4

この画像対話モデルは、MiniGPT-4をベースにしています。
https://github.com/Vision-CAIR/MiniGPT-4

MiniGPT-4のVicuna + BLIP-2をrinna 3.6b + BLIP-2にした感じ。
Japanese MiniGPT-4: rinna 3.6bとBLIP-2を組み合わせてマルチモーダルチャットのモデルを作る

動かすとこんな感じ。大きく外れてはないな、という返答です。あと、簡潔。

メモリは11.4GBくらい使うので、12GB GPUだときつそう。

導入

導入として公式で書いてある手順はこんな感じ。MiniGPT-4をGitHubからcloneして22d8888ブランチを使う、と。

git clone https://github.com/Vision-CAIR/MiniGPT-4.git
cd ./MiniGPT-4
git checkout 22d8888 # latest version as of July 31, 2023.

そして、rinna用にカスタマイズしたMiniGPT-4のスクリプトとBLIP2-LLMのcheckpoint.pthをダウンロード。

wget https://huggingface.co/rinna/bilingual-gpt-neox-4b-minigpt4/resolve/main/customized_mini_gpt4.py
wget https://huggingface.co/rinna/bilingual-gpt-neox-4b-minigpt4/resolve/main/checkpoint.pth

Windowsの場合はwgetを使うにはPowerShellを使うのだけど、オプションなしだと単にネットからデータを読むだけになってしまうので-OutFileを付けて保存先を指定する。
そうすると「書き込んでいます」が出る。「読み込んでいます」だと読み込むだけになる。

あとはCUDAとかPyTorchとかTransformersとかsentencepieceとか、rinna 3.6bが動く状態を作っておく。

bitsandbytesを使っているのだけど、Windowsの場合はpipからインストールしても使えないので、こちらを。
https://github.com/jllllll/bitsandbytes-windows-webui

0.39.1を使っていますが、新しいものでも大丈夫だと思う。

python -m pip install bitsandbytes==0.39.1 --prefer-binary --extra-index-url=https://jllllll.github.io/bitsandbytes-windows-webui

あと、いままで使ってなかったものとして、omegaconf、iopath、timm、webdataset、decordのインストールが必要だった。

動かす

そしたらHow to use the model のところのコードが動かせるはず。
No module named 'decord'のようなエラーが出たらpip installしていく。

7.74GBのモデルのダウンロードなどがあったあと、こんな感じで表示される。

Loading VIT
freeze vision encoder
Loading VIT Done
Loading Q-Former
freeze Qformer
Loading Q-Former Done
Loading LLM
Loading LLM Done
Load BLIP2-LLM Checkpoint: ./checkpoint.pth
ユーザー: <Img><ImageHere></Img> What can you see?
システム: a cat on a table with a laptop
ユーザー: 猫はどんな体勢をしていますか?
システム:
寝ています

コードを見る

モデルをCustomizedMiniGPT4として定義してますね。

model = CustomizedMiniGPT4(gpt_neox_model="rinna/bilingual-gpt-neox-4b")
tokenizer = model.gpt_neox_tokenizer

そしてBIP2-LLMを読み込み

ckpt = torch.load(ckpt_path, map_location="cpu")
model.load_state_dict(ckpt['model'], strict=False)

会話に使う画像を読み込み。

image_url = "https://huggingface.co/rinna/bilingual-gpt-neox-4b-minigpt4/resolve/main/sample.jpg"
raw_image = Image.open(requests.get(image_url, stream=True).raw).convert('RGB')

そしてBLIP2-LLMを使って埋め込みベクトルに変換

vis_processor = Blip2ImageEvalProcessor()
image = vis_processor(raw_image).unsqueeze(0).to(model.device)
image_emb = model.encode_img(image)

プロンプトと画像埋め込みを結合した埋め込みベクトルを取得

embs = model.get_context_emb(prompt, [image_emb])

で、生成

output_ids = model.gpt_neox_model.generate(
    inputs_embeds=embs,
    max_new_tokens=512,
    do_sample=True,
    temperature=1.0,
    top_p=0.85,
    pad_token_id=tokenizer.pad_token_id,
    bos_token_id=tokenizer.bos_token_id,
    eos_token_id=tokenizer.eos_token_id
)

output = tokenizer.decode(output_ids.tolist()[0], skip_special_tokens=True)

UIをつける

いろいろ試したいのでGradioでUIを作る

with gr.Blocks() as demo:
  gr.Markdown("## multi modal rinna")
  imgIn = gr.Image(lambda: raw_image, type="pil")
  with gr.Row():
    upload = gr.Button("Upload", variant="primary")
    def_img = gr.Button("Default")
    upload.click(load_image, inputs=imgIn)
    def_img.click(init_image, outputs=imgIn)
  with gr.Row():
    with gr.Column():
      question = gr.Textbox(lines=3, placeholder="質問を")
      submit = gr.Button("Submit", variant="primary")
      with gr.Row():
        default = gr.Button("Default")
        clear = gr.Button("Clear")
        default.click(lambda: "画像を説明して", outputs=question)
        clear.click(lambda: "", outputs=question)
    answer = gr.Textbox(lines=3)
    submit.click(generate, inputs=question, outputs=answer)

demo.launch()

そしたら冒頭のUIができる。画面を横分割して画像を左側でもよかったな。

ソース全体はこちら。動かすとき、画像をD&DしただけではLLMに送られていないので気をつけてください。Uploadボタンを押す必要があります。
https://gist.github.com/kishida/ee107e002546ce2ab26c5d9a6eac33b1

分厚く難しそうな技術書を素敵だと思ったら今必要なそうでも買っておくべき

鈍器が届いたんですよ。
カード履歴みてたら昨日13,200円の見覚えのないAmazonからの請求があって、「本でもなさそうだしAmazon見ても履歴ないし謎い」とか思ったら宅急便がきて。。。

まあ、注文してた「コンパクトデータ構造」が来てたわけだけど。
asin406512476X:detail

予約したのが6/16で直近の履歴を見てもなくて、そして今日が発売日なので昨日決済されて発送された、ってことらしい。

紙が固めでめくりやすい。というか、めくるのが楽しい。変なデータ構造がいっぱい載ってるのもよい。図も多いので、絵本みたい。内容的には読むの大変そうだけど、落ち着いてゆっくり読めば大丈夫そう。

内容としては、圧縮した状態でいろいろ操作ができるデータ構造を考えようぜ、という感じ。
Wikipediaだと「簡潔データ構造」の項目を見ると載ってる。

と思ったら、こういう本があった。

そして買っていた?

しかし家を探してもデータ化したフォルダ探しても見当たらない。記憶もないな。で、購入履歴を確認したら、だれかの欲し芋で送ってたっぽい。

ところで本題。
こういう分厚くて難しそうで素敵な本は、読むかなーどうかなーと悩むのなら買っておくほうがいい。
というのも、だいたいすぐ絶版して、中古も値上がりして気軽に読めないになる。

例えば「コンピュータプログラミングの概念・技法・モデル」はプログラミング言語の機能をいろいろ分類した本で、オブジェクト指向言語とはどういう位置づけになるのかという話をするときに確認してもらいたいんだけど、いま中古で4万円。

アルゴリズムデザイン」も一時絶版状態で、12万とかで売られてるのを見た。
いまは在庫復活して17,000+税になっているけど、買ったときは15,000+税だったな。Amazonの書影の裏表紙見るとわかります。
これも広範囲に網羅されてるし読みやすいし、同じ内容を埋めようとして4000円くらいの本を5冊買うとかを考えると割にあう。

まあ、そんな感じで、よさげと思った本は買っておけ、という話ですね。

実はサーブレットの勉強もSpring Bootを使うほうが楽なのでは

サーブレットで面倒なのはTomcatとの付き合いです。
Spring BootでSpring Webを使うと組み込みTomcatが動くので、Tomcatのことを気にしなくてよくなりますね。
そこでサーブレット動かすと勉強しやすいんでは、と思ったので試してみます。

まず、spring initializrでSpring Webを追加したプロジェクトを作ります。
https://start.spring.io/

このリンクから、設定済みのspring initializrを開けます。Mavenにしているので、Gradleがいい人は選択しなおしてください。
https://start.spring.io/#!type=maven-project&language=java&platformVersion=3.1.1&packaging=jar&jvmVersion=17&groupId=com.example&artifactId=demo&name=ServletDemo&description=Servlet%20Demo%20project%20for%20Spring%20Boot&packageName=com.example.servletdemo&dependencies=web

[GENERATE]ボタンを押してダウンロードしたzipを解凍します。こんな感じになっているはず。

アプリケーションクラスに @ServletComponentScan を付けます。

package com.example.servletdemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;

@SpringBootApplication
@ServletComponentScan
public class ServletDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(ServletDemoApplication.class, args);
    }

}

そしてサーブレットクラスを定義します。
サーブレットのパッケージがjakartaになってるのは感慨深さ。

package com.example.servletdemo;

import java.io.IOException;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

@WebServlet(urlPatterns = "/hello")
public class SampleServlet extends HttpServlet{

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        resp.getWriter().println("""
            <h1>Hello Servlet</h1>
            Hello!
            """);
    }
    
}

アプリケーションクラスを実行させると、Spring Bootが起動します。

http://localhost:8080/hello にアクセスすると・・・

できました!
これでいいのでは。オートリロードなども使えると思うので、かなり楽ができそう。

ただし、JSPを動かそうとすると結構めんどいので、それなら最初からJakartaEEを使うほうがいいかも。これもアプリサーバーのインストールや起動、デプロイなどをやらなくていいようになっています。
起動やアクセスポートはランタイムごとに違うので、ダウンロード時についてくるreadmeを確認する必要があります。
https://start.jakarta.ee/