CLOVER🍀

That was when it all began.

Eclipse Starter for Jakarta EEを試す

これは、なにをしたくて書いたもの?

Jakarta EEのプロジェクトのとっかかりを作れる、Eclipse Starter for Jakarta EEというものがあることは知っていたのですが、使わないまま
存在を完全に忘れていたので、1度試しておくことにしました。

Eclipse Starter for Jakarta EE

Eclipse Starter for Jakarta EEは、こちらのサイトになります。

Eclipse Starter for Jakarta EE

こんな感じで、

をそれぞれ選択していきます。

あとは「Generate」ボタンを押すと、jakartaee-hello-world.zipというzipファイルがダウンロードできます。

試してみる

今回の環境は、こちらです。

$ java --version
openjdk 17.0.8.1 2023-08-24
OpenJDK Runtime Environment (build 17.0.8.1+1-Ubuntu-0ubuntu122.04)
OpenJDK 64-Bit Server VM (build 17.0.8.1+1-Ubuntu-0ubuntu122.04, mixed mode, sharing)


$ mvn --version
Apache Maven 3.9.4 (dfbb324ad4a7c8fb0bf182e6d91b0ae20e3d2dd9)
Maven home: $HOME/.sdkman/candidates/maven/current
Java version: 17.0.8.1, vendor: Private Build, runtime: /usr/lib/jvm/java-17-openjdk-amd64
Default locale: ja_JP, platform encoding: UTF-8
OS name: "linux", version: "5.15.0-83-generic", arch: "amd64", family: "unix"

Eclipse Starter for Jakarta EEで指定する内容は、先程のキャプチャーの通りなのですが

で作成したzipファイルをダウンロードして、展開。

$ unzip jakartaee-hello-world.zip
$ cd jakartaee-hello-world

中身はこんな感じですね。

$ tree
.
├── Dockerfile
├── README.md
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
    └── main
        ├── java
        │   └── org
        │       └── eclipse
        │           └── jakarta
        │               └── hello
        │                   ├── Hello.java
        │                   └── HelloWorldResource.java
        └── webapp
            ├── WEB-INF
            │   └── web.xml
            ├── images
            │   └── jakartaee_logo.jpg
            └── index.html

10 directories, 10 files

中身を少し見てみましょう。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>

        <groupId>org.eclipse</groupId>
        <artifactId>jakartaee-hello-world</artifactId>
        <version>0.1-SNAPSHOT</version>
        <packaging>war</packaging>

        <name>jakartaee-hello-world</name>
        <description>
                This is a very simple Jakarta EE application generated by the official Eclipse Starter.
        </description>

        <properties>
                <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
                <project.report.sourceEncoding>UTF-8</project.report.sourceEncoding>
                <maven.compiler.release>17</maven.compiler.release>
                <jakartaee-api.version>10.0.0</jakartaee-api.version>
                <wildfly.version>27.0.1.Final</wildfly.version>
                <compiler-plugin.version>3.11.0</compiler-plugin.version>
                <war-plugin.version>3.3.2</war-plugin.version>
                <wildfly-plugin.version>4.1.0.Final</wildfly-plugin.version>
        </properties>

        <dependencies>
                <dependency>
                        <groupId>jakarta.platform</groupId>
                        <artifactId>jakarta.jakartaee-api</artifactId>
                        <version>${jakartaee-api.version}</version>
                        <scope>provided</scope>
                </dependency>
        </dependencies>

        <build>
                <finalName>jakartaee-hello-world</finalName>
                <plugins>
                        <plugin>
                                <groupId>org.apache.maven.plugins</groupId>
                                <artifactId>maven-compiler-plugin</artifactId>
                                <version>${compiler-plugin.version}</version>
                        </plugin>
                        <plugin>
                                <artifactId>maven-war-plugin</artifactId>
                                <version>${war-plugin.version}</version>
                                <configuration>
                                        <failOnMissingWebXml>false</failOnMissingWebXml>
                                </configuration>
                        </plugin>

                        <!-- Execute 'mvn clean package wildfly:dev' to run the application. -->
                        <plugin>
                                <groupId>org.wildfly.plugins</groupId>
                                <artifactId>wildfly-maven-plugin</artifactId>
                                <version>${wildfly-plugin.version}</version>
                                <configuration>
                                        <version>${wildfly.version}</version>
                                        <server-config>standalone-full.xml</server-config>
                                </configuration>
                        </plugin>
                </plugins>
        </build>
</project>

src/main/java/org/eclipse/jakarta/hello/HelloWorldResource.java

package org.eclipse.jakarta.hello;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.MediaType;

@Path("hello")
public class HelloWorldResource {

        @GET
        @Produces({ MediaType.APPLICATION_JSON })
        public Hello hello(@QueryParam("name") String name) {
                if ((name == null) || name.trim().isEmpty())  {
                        name = "world";
                }

                return new Hello(name);
        }
}

src/main/java/org/eclipse/jakarta/hello/Hello.java

package org.eclipse.jakarta.hello;

public class Hello {

        private String name;

        public Hello(String name) {
        this.name = name;
        }

        public String getHello(){
                return name;
        }
}

src/main/webapp/WEB-INF/web.xml

<web-app version="6.0"
        xmlns="https://jakarta.ee/xml/ns/jakartaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd">
        <servlet>
                <servlet-name>jakarta.ws.rs.core.Application</servlet-name>
        </servlet>
        <servlet-mapping>
                <servlet-name>jakarta.ws.rs.core.Application</servlet-name>
                <url-pattern>/rest/*</url-pattern>
        </servlet-mapping>
        <welcome-file-list>
                <welcome-file>index.html</welcome-file>
        </welcome-file-list>
</web-app>

Dockerfile

FROM quay.io/wildfly/wildfly
COPY target/jakartaee-hello-world.war /opt/jboss/wildfly/standalone/deployments/
CMD ["/opt/jboss/wildfly/bin/standalone.sh", "-b", "0.0.0.0", "-bmanagement", "0.0.0.0", "-c","standalone-full.xml"]

主要なファイルはこんなところでしょうか。WildFlyのバージョンが27.0.1.Finalと微妙に古いですね。

実行方法はREADME.mdに書かれているので、まずは起動してみます。

$ mvn clean package wildfly:dev

確認。

$ curl localhost:8080/jakartaee-hello-world/rest//hello
{"hello":"world"}


$ curl localhost:8080/jakartaee-hello-world/rest//hello?name=jakarta
{"hello":"jakarta"}

OKですね。

wildfly:devで起動しているので、ソースコードを書き換えると

        @GET
        @Produces({ MediaType.APPLICATION_JSON })
        public Hello hello(@QueryParam("name") String name) {
                if ((name == null) || name.trim().isEmpty())  {
                        name = "world";
                }

                name = name + "!!";

                return new Hello(name);
        }

変更が検知されて、すぐにビルド&再デプロイされます。

[INFO] Changes detected - recompiling the module! :source
[INFO] Compiling 2 source files with javac [debug release 17] to target/classes
[INFO] Exploding webapp
[INFO] Assembling webapp [jakartaee-hello-world] in [/path/to/jakartaee-hello-world/target/jakartaee-hello-world]
[INFO] Processing war project
[INFO] Copying webapp resources [/path/to/jakartaee-hello-world/src/main/webapp]
22:54:17,068 INFO  [org.wildfly.extension.undertow] (ServerService Thread Pool -- 23) WFLYUT0022: Unregistered web context: '/jakartaee-hello-world' from server 'default-server'
22:54:17,101 INFO  [org.jboss.as.server.deployment] (MSC service thread 1-5) WFLYSRV0028: Stopped deployment jakartaee-hello-world (runtime-name: jakartaee-hello-world.war) in 38ms
22:54:17,105 INFO  [org.jboss.as.server.deployment] (MSC service thread 1-8) WFLYSRV0027: Starting deployment of "jakartaee-hello-world" (runtime-name: "jakartaee-hello-world.war")
22:54:17,307 INFO  [org.wildfly.extension.undertow] (ServerService Thread Pool -- 90) WFLYUT0021: Registered web context: '/jakartaee-hello-world' for server 'default-server'
22:54:17,324 INFO  [org.jboss.as.server] (management-handler-thread - 1) WFLYSRV0013: Redeployed "jakartaee-hello-world.war"

〜省略〜

確認。

$ curl localhost:8080/jakartaee-hello-world/rest//hello
{"hello":"world!!"}


$ curl localhost:8080/jakartaee-hello-world/rest//hello?name=jakarta
{"hello":"jakarta!!"}

まあ、これはWildFlyの話ですが。

Eclipse Starter for Jakarta EEのGitHubリポジトリー

Eclipse Starter for Jakarta EEはGitHubにソースコードが公開されています。こちらですね。

GitHub - eclipse-ee4j/starter: Eclipse Starter for Jakarta EE

検索しても見つかりますし、Webサイトのissue trackerの向き先がGitHubになっていることでも気づくことができます。

README.mdを見るとわかるのですが、Web UIだけではなくてMavenアーキタイプとしても実行できます。

Eclipse Starter for Jakarta EE / Generate Jakarta EE Project Using Archetypes

MavenアーキタイプとWeb UIが含まれているリポジトリーになるので、実際にWebサイトがどのバージョンで動作しているのか
わからなくなるのですが…現時点だとMavenアーキタイプは2.2.0、2.2.0を使うWeb UIは2.0.2のようです。

https://github.com/eclipse-ee4j/starter/tree/archetype-2.2.0

https://github.com/eclipse-ee4j/starter/tree/ui-2.0.2

今回は、Mavenアーキタイプの2.2.0のタグで見ていくことにしましょう。

ディレクトリはこちら。

https://github.com/eclipse-ee4j/starter/tree/archetype-2.2.0/archetype

コマンドの例として以下が書かれていますが、どういったものが指定できるのか(指定するのか)気になりますね。

$ mvn archetype:generate -DarchetypeGroupId="org.eclipse.starter" -DarchetypeArtifactId="jakarta-starter"

設定できるプロパティは、以下に定義されています。

  <requiredProperties>
    <requiredProperty key="groupId">
      <defaultValue>org.eclipse</defaultValue>
    </requiredProperty>
    <requiredProperty key="artifactId">
      <defaultValue>jakartaee-hello-world</defaultValue>
    </requiredProperty>
    <requiredProperty key="version">
      <defaultValue>0.1-SNAPSHOT</defaultValue>
    </requiredProperty>
    <requiredProperty key="package">
      <defaultValue>org.eclipse</defaultValue>
    </requiredProperty>
    <requiredProperty key="jakartaVersion">
      <defaultValue>10</defaultValue>
      <validationRegex>^(8|9|9.1|10)$</validationRegex>
    </requiredProperty>
    <requiredProperty key="profile">
      <defaultValue>full</defaultValue>
      <validationRegex>^(core|web|full)$</validationRegex>
    </requiredProperty>
    <requiredProperty key="javaVersion">
      <defaultValue>17</defaultValue>
      <validationRegex>^(8|11|17)$</validationRegex>
    </requiredProperty>
    <requiredProperty key="docker">
      <defaultValue>no</defaultValue>
      <validationRegex>^(no|yes)$</validationRegex>
    </requiredProperty>
    <requiredProperty key="runtime">
      <defaultValue>none</defaultValue>
      <validationRegex>^(none|glassfish|open-liberty|payara|tomee|wildfly)$</validationRegex>
    </requiredProperty>
  </requiredProperties>

https://github.com/eclipse-ee4j/starter/blob/archetype-2.2.0/archetype/src/main/resources/META-INF/maven/archetype-metadata.xml

雰囲気、なんとなくわかりますね。

アプリケーションサーバーなどのバージョンがどこで決まるかというと、pom.xml内にテンプレートが埋め込まれています。

#if (${profile} == 'core')
#set ($eeArtifactId = "jakarta.jakartaee-core-api")
#set ($wildflyConfiguration = "standalone")
#elseif (${profile} == 'web')
#set ($eeArtifactId = "jakarta.jakartaee-web-api")
#set ($wildflyConfiguration = "standalone")
#else
#set ($eeArtifactId = "jakarta.jakartaee-api")
#set ($wildflyConfiguration = "standalone-full")
#end
#if (${jakartaVersion} == '10')
#set ($eeApiVersion = "10.0.0")
#elseif (${jakartaVersion} == '9.1')
#set ($eeApiVersion = "9.1.0")
#elseif (${jakartaVersion} == '9')
#set ($eeApiVersion = "9.0.0")
#else
#set ($eeApiVersion = "8.0.0")
#end
#if (${jakartaVersion} == '8')
#set ($tomeeVersion = "8.0.14")
#set ($payaraVersion = "5.2022.5")
#set ($glassfishContainerId = "glassfish5x")
#if (${profile} == 'web')
#set ($glassfishUrl = "https://repo.maven.apache.org/maven2/org/glassfish/main/distributions/web/5.1.0/web-5.1.0.zip")
#else
#set ($glassfishUrl = "https://repo.maven.apache.org/maven2/org/glassfish/main/distributions/glassfish/5.1.0/glassfish-5.1.0.zip")
#end
#else
#set ($payaraVersion = "6.2023.5")
#set ($tomeeVersion = "9.0.0")
#set ($glassfishContainerId = "glassfish7x")
#if (${profile} == 'web')
#set ($glassfishUrl = "https://repo.maven.apache.org/maven2/org/glassfish/main/distributions/web/7.0.5/web-7.0.5.zip")
#else
#set ($glassfishUrl = "https://repo.maven.apache.org/maven2/org/glassfish/main/distributions/glassfish/7.0.5/glassfish-7.0.5.zip")
#end
#end
#if (${jakartaVersion} == '10')
#set ($wildflyVersion = "27.0.1.Final")
#else
#set ($wildflyVersion = "26.1.3.Final")
#end

https://github.com/eclipse-ee4j/starter/blob/archetype-2.2.0/archetype/src/main/resources/archetype-resources/pom.xml

試しに指定すると、こんな感じでしょうか。

$ mvn archetype:generate \
  -DarchetypeGroupId="org.eclipse.starter" \
  -DarchetypeArtifactId="jakarta-starter" \
  -DgroupId=org.example \
  -DartifactId=my-jakartaee-hello-world \
  -Dversion=0.0.1-SNAPSHOT \
  -Dpackage=org.example \
  -DjakartaVersion=10 \
  -Dprofile=web \
  -DjavaVersion=17 \
  -Ddocker=yes \
  -Druntime=wildfly \
  -DinteractiveMode=false

指定した項目が反映されていることが確認できます。

[INFO] Parameter: groupId, Value: org.example
[INFO] Parameter: artifactId, Value: my-jakartaee-hello-world
[INFO] Parameter: version, Value: 0.0.1-SNAPSHOT
[INFO] Parameter: package, Value: org.example
[INFO] Parameter: packageInPathFormat, Value: org/example
[INFO] Parameter: package, Value: org.example
[INFO] Parameter: javaVersion, Value: 17
[INFO] Parameter: groupId, Value: org.example
[INFO] Parameter: profile, Value: web
[INFO] Parameter: runtime, Value: wildfly
[INFO] Parameter: artifactId, Value: my-jakartaee-hello-world
[INFO] Parameter: version, Value: 0.0.1-SNAPSHOT
[INFO] Parameter: jakartaVersion, Value: 10
[INFO] Parameter: docker, Value: yes

できあがったプロジェクト内に移動。

$ cd my-jakartaee-hello-world

確認。

$ tree
.
├── Dockerfile
├── README.md
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
    └── main
        ├── java
        │   └── org
        │       └── example
        │           └── jakarta
        │               └── hello
        │                   ├── Hello.java
        │                   └── HelloWorldResource.java
        └── webapp
            ├── WEB-INF
            │   └── web.xml
            ├── images
            │   └── jakartaee_logo.jpg
            └── index.html

10 directories, 10 files

pom.xml

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>

        <groupId>org.example</groupId>
        <artifactId>my-jakartaee-hello-world</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <packaging>war</packaging>

        <name>jakartaee-hello-world</name>
        <description>
                This is a very simple Jakarta EE application generated by the official Eclipse Starter.
        </description>

        <properties>
                <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
                <project.report.sourceEncoding>UTF-8</project.report.sourceEncoding>
                <maven.compiler.release>17</maven.compiler.release>
                <jakartaee-api.version>10.0.0</jakartaee-api.version>
                <wildfly.version>27.0.1.Final</wildfly.version>
                <compiler-plugin.version>3.11.0</compiler-plugin.version>
                <war-plugin.version>3.3.2</war-plugin.version>
                <wildfly-plugin.version>4.1.0.Final</wildfly-plugin.version>
        </properties>

        <dependencies>
                <dependency>
                        <groupId>jakarta.platform</groupId>
                        <artifactId>jakarta.jakartaee-web-api</artifactId>
                        <version>${jakartaee-api.version}</version>
                        <scope>provided</scope>
                </dependency>
        </dependencies>

        <build>
                <finalName>jakartaee-hello-world</finalName>
                <plugins>
                        <plugin>
                                <groupId>org.apache.maven.plugins</groupId>
                                <artifactId>maven-compiler-plugin</artifactId>
                                <version>${compiler-plugin.version}</version>
                        </plugin>
                        <plugin>
                                <artifactId>maven-war-plugin</artifactId>
                                <version>${war-plugin.version}</version>
                                <configuration>
                                        <failOnMissingWebXml>false</failOnMissingWebXml>
                                </configuration>
                        </plugin>

                        <!-- Execute 'mvn clean package wildfly:dev' to run the application. -->
                        <plugin>
                                <groupId>org.wildfly.plugins</groupId>
                                <artifactId>wildfly-maven-plugin</artifactId>
                                <version>${wildfly-plugin.version}</version>
                                <configuration>
                                        <version>${wildfly.version}</version>
                                        <server-config>standalone.xml</server-config>
                                </configuration>
                        </plugin>
                </plugins>
        </build>
</project>

生成されるプロジェクトの元ネタは、こちらを参照しましょう。

https://github.com/eclipse-ee4j/starter/tree/archetype-2.2.0/archetype/src/main/resources/archetype-resources

こんなところでしょうか。

ちなみに、Web UIの方はJakarta EE 8で作られているみたいですね。

https://github.com/eclipse-ee4j/starter/blob/archetype-2.2.0/ui/pom.xml